如何使用ObjectAnimator基于拖动动作平滑地向上/向下动画视图?

时间:2013-04-13 05:41:02

标签: android performance android-animation nineoldandroids

我创建了一个视图,其中MapFragment占据了屏幕的前1/3,而ListView占据了屏幕的底部2/3。 ListView在其列表项的正上方有一个“句柄”,用户可以用它来向上或向下拖动整个ListView。一旦用户将手指从屏幕上移开,ListView应该为整个屏幕的壁橱顶部或底部边框设置动画。我到目前为止工作但动画不顺畅。在ListView开始向最近边缘动画之前,用户从屏幕上松开手指后会有明显的暂停。我正在使用ObjectAnimator的nineoldandroids实现,以便动画可用于预蜂窝设备。有任何想法吗?

以下是我的onTouch impl:

public boolean onTouch(View v, MotionEvent event) {
    final LayoutParams listLp = (LayoutParams) mListFrame.getLayoutParams();
    final int topMargin = -mHandleShadow.getHeight();
    final int middleMargin = getResources().getDimensionPixelSize(R.dimen.map_handle_margin_top);
    final int bottomMargin = getView().getHeight() - mHandle.getHeight() - mHandleShadow.getHeight();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mInitY = (int) event.getRawY();
            mTopMargin = listLp.topMargin;

            break;
        case MotionEvent.ACTION_MOVE:
            int y = mTopMargin + (int) event.getRawY() - mInitY;

            if (y >= -mHandleShadow.getHeight() && y <= (mViewHeight - mHandle.getHeight() - mHandleShadow.getHeight())) {
                listLp.topMargin = y;
                mListFrame.setLayoutParams(listLp);
            }

            break;
        case MotionEvent.ACTION_UP:
            if ((mInitY > event.getRawY() && mClosestAnchor == Anchor.MIDDLE) || (listLp.topMargin < middleMargin && mClosestAnchor == Anchor.BOTTOM)) {
                ObjectAnimator animator = ObjectAnimator.ofInt(AnimatorProxy.wrap(mListFrame), "topMargin", topMargin);
                animator.setInterpolator(new AccelerateInterpolator());
                animator.start();

                mClosestAnchor = Anchor.TOP;
            }
            else if ((mInitY < event.getRawY() && mClosestAnchor == Anchor.MIDDLE) || (listLp.topMargin > middleMargin && mClosestAnchor == Anchor.TOP)) {
                ObjectAnimator animator = ObjectAnimator.ofInt(AnimatorProxy.wrap(mListFrame), "topMargin", bottomMargin);
                animator.setInterpolator(new AccelerateInterpolator());
                animator.start();

                mClosestAnchor = Anchor.BOTTOM;
            }
            else {
                ObjectAnimator animator = ObjectAnimator.ofInt(AnimatorProxy.wrap(mListFrame), "topMargin", middleMargin);
                animator.setInterpolator(new AccelerateInterpolator());
                animator.start();

                mClosestAnchor = Anchor.MIDDLE;
            }

            break;
    }

    return true;
}

1 个答案:

答案 0 :(得分:8)

最后解决了谷歌的Chet Haase对此处发现的类似问题的回答。 https://stackoverflow.com/a/14780019/476005

在每一帧上调整视图的边距太昂贵,并且除非您正在移动的视图非常简单,否则将始终断断续续。所以要解决这个问题,我在OnTouch(...)方法中执行以下操作:

  1. On MotionEvent.ACTION_DOWN:将视图的高度设置为它的最大高度。
  2. On MotionEvent.ACTION_MOVE:将View的“y”属性设置为event.getRawY的动画,持续时间为0.
  3. On MotionEvent.ACTION_UP:将View的“y”属性设置为View的父级边缘之一。这里要做的重要事情是在onAnimationEnd中适当地设置View的高度。
  4. 我希望这对每个人都有帮助。