Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is view dragged with ViewDragHelper reset to its original position on layout()?

I am implementing a custom expandable action bar in my game. I am using ViewDragHelper to handle the dragging and flinging of the bar view, which is contained in a LinearLayout I subclassed to attach the ViewDragHelper.

The following links have been of great help to achieve this:

  • Tutorial on the ViewDragHelper: http://flavienlaurent.com/blog/2013/08/28/each-navigation-drawer-hides-a-viewdraghelper/
  • Mastering the Android touch system: https://www.youtube.com/watch?v=EZAoJU-nUyI (which has given me they key to make Views clickable and draggable)

The only issue I am encountering is the behavior of the layout() of my parent LinearLayout: on every call to layout() / onLayout(), the child draggable/expandable action bar is reset to its original position (the one set in the XML layout).

Why is that ?

(In my experience layout() never messes with the positions of views that have already been moved)

like image 261
Sébastien Avatar asked Apr 04 '14 14:04

Sébastien


2 Answers

The workaround I'm using is to record the view's offsets after each drag operation, and reapply them in onLayout(), e.g.

View mVdhView;
int mVdhXOffset;
int mVdhYOffset;

@Override
public void computeScroll() {
    if (dragHelper.continueSettling(true)) {
        postInvalidateOnAnimation();
    } else {
        mVdhXOffset = mVdhView.getLeft();
        mVdhYOffset = mVdhView.getTop();
    }
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);

      // Reapply VDH offsets
    mVdhView.offsetLeftAndRight(mVdhXOffset);
    mVdhView.offsetTopAndBottom(mVdhYOffset);
}
like image 113
user3452758 Avatar answered Oct 26 '22 00:10

user3452758


I encountered the same issue when playing with a DrawerLayout (a layout having draggable drawers), and was initially also surprised.

From reading the source, it seems ViewDragHelper uses offsetLeftAndRight() / offsetTopAndBottom() to visually shift any captured and dragged View, presumably to be able to be usable down to API 4.

To answer your question: layout is NOT messing with the positions of the View, it is just that by using the offset..() functions that ViewDragHelper is not hammering down the positioning of the View for you.

So, in your view's onLayout you'll have to account for any visual positioning done using ViewDragHelper. For example, in DrawerLayout this is internally tracked through a simple 'lp.onScreen' percentage field and in its onLayout() the corresponding shift is added to the parameters in a call to child.layout() for any dragged drawer child View.

like image 28
Dion Avatar answered Oct 26 '22 00:10

Dion