Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Custom View move back to original position when refreshing

I'm implementing a time picker which looks like this:

unfinished time picker

That yellow block is MyCustomView. When moving MyCustomView, I should calculate new date and set tvDate.

partial layout file:

<LinearLayout 
    android:orientation="vertical">

    <TextView android:id="@+id/tv_date">

    <RelativeLayout 
        android:id="@+id/rl">

        <MyCustomView
         android:layout_centerInParent="true"/>

        <OtherViews/>
    </RelativeLayout>
</LinearLayout>

code:

class MyCustomView extends View{

    // move listener
    public interface IMoveCallback{
        void update(int index);
    }

    private IMoveCallback listener = null; 

    // set listener
    public void setMoveCallback(IMoveCallback callback){
        this.listener = callback;
    }

    @Override
    protected void onDraw(Canvas c){
        super.onDraw(c);
        // draw yellow block and four arrows here.
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        processDrag(v, event);
        invalidate();
        return false;
    }

    private void processDrag(View v, MotionEvent event){
        // calculate new position(left, top, right, bottom)
        v.layout(newLeft, newTop, newRight, newBottom); 
        if(listener != null){
            // calculate index by new position
            listener.update(index);
        }
    }
}

class MainActivity extends Activity implements MyCustomView.IMoveCallback{

    MyCustomView view; // view.setMoveCallback(MainActivity.this)

    @Override
    public void update(int index){
        tvDate.setText(String.valueOf(System.currentTimeMillis()))//update tvDate
    }
}

If tvDate.setText() is removed, MyCustomView follows the finger, like this:

enter image description here

If I update tvDate, MyCustomView moves back to the center of rl:

enter image description here

I don't think it an activity-lifecycle issue. Someone mentioned ((MarginLayoutParams)rl.getLayoutParams()).topMargin but did not explain why.
Anybody can help me?

like image 922
Anthony Cooper Avatar asked Nov 09 '22 18:11

Anthony Cooper


1 Answers

Your solution is to invalidate your CustomView after you TextView.setText() setText() before you layout or pass in values for your left, rigth, ...

private void processDrag(View v, MotionEvent event){       
    if(listener != null){
        // calculate index by new position
        listener.update(index);
    }        
    // calculate new position(left, top, right, bottom)
    v.layout(newLeft, newTop, newRight, newBottom); 
}
//i think you should take out invalidate() in your onTouch()

Why? TextView.setText() triggers invalidate & requestLayout() at them same time to force a quick layout, but Invalidate() just tells its parent that it is dirty, so it needs to do a top down layout pass.

(im confused so i won't continue to back this up, hence i jump). Your TextView is inside a parent layout who's grand child is your custom view, and invalidate(), re-lays all of them hence sends your custom view back to its position, however if you exclude that, and call an explicit invalidate() in your Custom view it tells it parent that its dirty and the same process happens, but this time only with the RelativeLayout

user: Zaid Qureshi has already made this points known to you.

Also i do not know if you know that the layoutParams being given to your customView is from the parent who you do not control much but the os, and the injected Params are what is uses to layout and give padding etc etc to your View, and since you do not lay them out but just passes positions.

Hope i make sense to you & it helps

like image 190
Elltz Avatar answered Nov 14 '22 23:11

Elltz