5

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?

Anthony Cooper
  • 465
  • 2
  • 15

2 Answers2

1

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

Elltz
  • 10,730
  • 4
  • 31
  • 59
0

You need to save the location of your view and render it at the same spot when the activity resumes(coming back from home) or starts(coming back after pressing back). This Picture shows methods you can override to achieve that such as onPause when losing focus etc.

EDIT

From the looks of it, it is resetting back to its original state. Post more about how you are setting the location etc. If that is a view you are moving. Then implement a on drag listener instead of that update. And let me know how that works out.

Zaid Qureshi
  • 1,203
  • 1
  • 10
  • 15
  • I set the location by `v.layout(left, top, right, bottom)` in `MyCustomView.onTouch(View v, MotionEvent motionEvent)` – Anthony Cooper Mar 09 '16 at 07:24
  • And it only happens when you call the update method? Have tried doing instead v.layout, do this.layout.. Also try updating the layout after you update the text maybe. – Zaid Qureshi Mar 09 '16 at 07:30
  • Yes, it only happens when `tvDate.setText()`. – Anthony Cooper Mar 09 '16 at 07:34
  • Try getting rid of your invalidate. Because TextView may already be calling that to refresh the views. Also store you new left right positions, and assign it again to the layout before drawing, maybe that will help. So instead of v.layout do this layout, and try doing it again before drawing – Zaid Qureshi Mar 09 '16 at 07:42
  • Also return true in your onTouch because you are interested in the other events from this view – Zaid Qureshi Mar 09 '16 at 07:43
  • Nothing changed. @Zaid Qureshi – Anthony Cooper Mar 11 '16 at 01:30
  • Someone says, when `View` wrapped into `LinearLayout` or `RelativeLayout`, `View.getLayoutParams() instanceof MarginLayoutParams.class == true`, this `MarginLayoutParams` causing `MyCustomView` back to original location. `MarginLayoutParams.setTopMargin()` solves his or her problem, but it is not work for me. – Anthony Cooper Mar 11 '16 at 01:43
  • If you are interested in his or her solution, check this Chinese website: http://blog.csdn.net/Sasoritattoo/article/details/39473809 – Anthony Cooper Mar 11 '16 at 01:51
  • I am not sure how that would effect you. The only problem is that somehow the values are resetting back to the original position. Where do you set the original position? – Zaid Qureshi Mar 11 '16 at 16:28
  • try implementing how [this answer](http://stackoverflow.com/a/9398861/4667831) implements it – Zaid Qureshi Mar 11 '16 at 16:32
  • @Elltz she might be right. When `tvDate.setText()` I do not lay them out but just pass positions. Instead of `v.layout()`, [that answer](http://stackoverflow.com/questions/9398057/android-move-a-view-on-touch-move-action-move/9398861#9398861) you provided could be a better solution. – Anthony Cooper Mar 14 '16 at 06:44