为什么将ViewDragHelper拖动的视图重置为layout()上的原始位置?

时间:2014-04-04 14:16:01

标签: android android-linearlayout viewdraghelper

我正在游戏中实现自定义可扩展操作栏。 我正在使用ViewDragHelper来处理条形视图的拖动和拖动,该视图包含在LinearLayout I子类中以附加ViewDragHelper。

以下链接对实现这一目标有很大帮助:

我遇到的唯一问题是我的父LinearLayout的布局()的行为:每次调用layout() / onLayout()时,子项可拖动/可扩展操作栏重置到其原始位置(XML布局中设置的位置)。

为什么?

(根据我的经验layout()从不会对已被移动的观点的位置感到困惑)

5 个答案:

答案 0 :(得分:11)

我正在使用的解决方法是在每次拖动操作后记录视图的偏移量,并在onLayout()中重新应用它们,例如

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);
}

答案 1 :(得分:2)

我在玩DrawerLayout(布局有可拖动的抽屉)时遇到了同样的问题,最初也很惊讶。

从阅读源代码看,似乎ViewDragHelper使用offsetLeftAndRight()/ offsetTopAndBottom()来直观地移动任何捕获和拖动的视图,大概可以使用到API 4。

回答你的问题:布局不会弄乱视图的位置,只是通过使用偏移..()函数,ViewDragHelper没有打击视图的定位对你而言。

因此,在您查看的onLayout中,您必须考虑使用ViewDragHelper完成的任何视觉定位。例如,在DrawerLayout中,这是通过一个简单的lp.onScreen'百分比字段,在其onLayout()中,相应的移位被添加到对任何拖动的抽屉子视图的child.layout()调用中的参数。

答案 2 :(得分:2)

这个答案有点晚了,但是在调用requestLayout()时你的内容被转发到其原始位置的原因(很可能)是因为onLayout()中的代码没有考虑到这些变化到意见的位置。

在flavienlaurent示例中,他的布局代码将可拖动视图定位在左侧位置0,但顶部位置使用全局范围变量mTop,后者在回调onViewPositionChanged(android.view.View, int, int, int, int)内修改为top值。您需要跟踪更改的值并将其带入onLayout()内部。

保持与拖动视图捆绑在一起的位置更改的一种简单方法是将它们存储在LayoutParams内部,并检索布局代码中的主题。如果您希望在布局中包含多个可拖动视图,这将非常有用。这种模式的一个很好的例子是Android SDK DrawerLayout(NavigationDrawer)的source code。在自定义LayoutParams内部类中查看类的底部。它有一个字段onScreen,类型为float。此变量用于存储可拖动视图的位置差异(相对于视图原点),并在setDrawerViewOffset()中更新。

另一种模式是做用户@ user3452758推荐的那种模式,但如果您想要拥有多个可拖动的视图,那么这将很难跟踪。

答案 3 :(得分:1)

抱歉,我不知道调用layout()的原因,但也许您的一个视图如ViewPager调用getView(查看parentView)。

无论如何,我假设你使用像this blog这样的DragViewHelper来描述。 所以有一个让人的方法 OnLayoutChangeListener 将布局移动到以前的位置。

MyActivity.java

'

因此,当调用layout()时,方法isMoving应该被启动 - 但看起来它并没有。因为DragViewHelper在STATE_IDLE中。我感谢你通过user3452758回答的伎俩。您需要在方法computeScroll()中的自定义滑动布局中设置标记,以便在正确的时间启用isMoving == true。

SlidingLayout.java

//parent
rlOuterView = (SlidingLayout) findViewById(R.id.sl_sliding_view);
//child - slides up/down
rlAppBarFooter = (RelativeLayout) findViewById(R.id.rl_footer);
        rlMainView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if( rlOuterView.isMoving() ){
                    v.setTop(oldTop);
                    v.setBottom(oldBottom);
                    v.setLeft(oldLeft);
                    v.setRight(oldRight);
                }
            }
        });

答案 4 :(得分:0)

您只需要添加以下代码即可:

@Override
public void onViewPositionChanged(@NonNull View changedView, int left, int top,
                                              int dx, int dy) {
        int right = getMeasuredWidth() - left - changedView.getMeasuredWidth();
        int bottom = getMeasuredHeight() - top - changedView.getMeasuredHeight();
        setLayout(left, top, right, bottom, changedView);
        super.onViewPositionChanged(changedView, left, top, dx, dy);
}
private void setLayout(int l, int t, int r, int b, View dragView) {
        MarginLayoutParams layoutParams = (MarginLayoutParams) dragView.getLayoutParams();
        layoutParams.setMargins(l, t, r, b);
        dragView.setLayoutParams(layoutParams);
}