首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用RecyclerView实现“反弹”ItemTouchHelper.Callback动画

用RecyclerView实现“反弹”ItemTouchHelper.Callback动画
EN

Stack Overflow用户
提问于 2015-09-25 14:45:19
回答 1查看 3.1K关注 0票数 1

我正在尝试使用扩展RecyclerViewHelper类在我的ItemTouchHelper.Callback行中创建一个动画。

ItemTouchHelper默认的“滑动”行为是,如果以足够的速度滑动一行,它就会从视图中消失(即滑动到错误)。在我的例子中,我想要创建一个动画,如果发生这样的事件,将使行直接反弹。

我已经能够创建一个ValueAnimator,如果它是从屏幕上滑动的话,就可以将该行动画回视图。但是,问题是,我无法让父ItemTouchHelper类认识到它存储的x值已经从行的宽度(因此它完全脱离屏幕)更改为0 (以便它回到屏幕上)。

这意味着,每当我在行完成自定义动画之后与它交互时,它的行为就好像该行仍然处于脱离屏幕的状态,即使它是完全可见的。这通常意味着按下它意味着行从X0位置跳转到行宽的X位置,然后从屏幕的边缘再次显示动画。在完全重置并再次正常运行之前,它会做几次这样的操作。

这段视频将有助于显示问题。由于前两次滑动不是抛出屏幕,默认行为有效。然而,当行被从屏幕上划掉并反弹回来后,点击行显示它从右边的边缘向后回击:

下面是我用来执行动画的代码:

代码语言:javascript
复制
public class CustomItemTouchHelper extends ItemTouchHelper.Callback {

    private RecoverAnimation ra;
    private boolean animatorRunning;

//...

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        final float per = (dX/viewHolder.itemView.getWidth());
        if (per > 0.8F && !animatorRunning && !isCurrentlyActive) {
            ra = new RecoverAnimation(c, recyclerView, viewHolder, ItemTouchHelper.ANIMATION_TYPE_SWIPE_CANCEL, actionState, dX, dY, 0, 0);
            ra.start();
        } else {
            getDefaultUIUtil().onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState, isCurrentlyActive);
        }
    }

//...

注意,这个内部类RecoverAnimation是从ItemTouchHelper源代码中提取的:

代码语言:javascript
复制
private class RecoverAnimation implements AnimatorListenerCompat {

    final float mStartDx;

    final float mStartDy;

    final float mTargetX;

    final float mTargetY;

    final Canvas mCanvas;

    final RecyclerView mRecyclerView;

    final RecyclerView.ViewHolder mViewHolder;

    final int mActionState;

    private final ValueAnimatorCompat mValueAnimator;

    float mX;

    float mY;

    // if user starts touching a recovering view, we put it into interaction mode again,
    // instantly.
    boolean mOverridden = false;

    private boolean mEnded = false;

    private float mFraction;

    public RecoverAnimation(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                            int actionState, float startDx, float startDy, float targetX, float targetY) {

        mRecyclerView = recyclerView;
        mCanvas = c;

        mActionState = actionState;
        mViewHolder = viewHolder;
        mStartDx = startDx;
        mStartDy = startDy;
        mTargetX = targetX;
        mTargetY = targetY;
        mValueAnimator = AnimatorCompatHelper.emptyValueAnimator();
        mValueAnimator.addUpdateListener(
                new AnimatorUpdateListenerCompat() {
                    @Override
                    public void onAnimationUpdate(ValueAnimatorCompat animation) {
                        setFraction(animation.getAnimatedFraction());
                        update();
                    }
                });
        mValueAnimator.setTarget(viewHolder.itemView);
        mValueAnimator.addListener(this);
        setFraction(0f);
    }

    public void setDuration(long duration) {
        mValueAnimator.setDuration(duration);
    }

    public void start() {
        animatorRunning = true;
        mViewHolder.setIsRecyclable(false);
        mValueAnimator.start();
    }

    public void cancel() {
        mValueAnimator.cancel();
    }

    public void setFraction(float fraction) {
        mFraction = fraction;
    }

    /**
     * We run updates on onDraw method but use the fraction from animator callback.
     * This way, we can sync translate x/y values w/ the animators to avoid one-off frames.
     */
    public void update() {
        if (mStartDx == mTargetX) {
            mX = ViewCompat.getTranslationX(mViewHolder.itemView);
        } else {
            mX = mStartDx + mFraction * (mTargetX - mStartDx);
        }
        if (mStartDy == mTargetY) {
            mY = ViewCompat.getTranslationY(mViewHolder.itemView);
        } else {
            mY = mStartDy + mFraction * (mTargetY - mStartDy);
        }
        getDefaultUIUtil().onDraw(mCanvas, mRecyclerView, mViewHolder.itemView, mX, mY, mActionState, false);
    }

    @Override
    public void onAnimationStart(ValueAnimatorCompat animation) {

    }

    @Override
    public void onAnimationEnd(ValueAnimatorCompat animation) {
        animatorRunning = false;
        mEnded = true;
        getDefaultUIUtil().onDraw(mCanvas, mRecyclerView, mViewHolder.itemView, 0, 0, ItemTouchHelper.ACTION_STATE_IDLE, false);
        getDefaultUIUtil().clearView(mViewHolder.itemView);
    }

    @Override
    public void onAnimationCancel(ValueAnimatorCompat animation) {
        setFraction(1f); //make sure we recover the view's state.
    }

    @Override
    public void onAnimationRepeat(ValueAnimatorCompat animation) {

    }
}

我能做些什么来解决这个问题,还是根本不可能(现在)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-07 11:37:05

以下解决方案将反弹回收查看项目,而不实现您的自定义RecoverAnimation类。

代码语言:javascript
复制
    public class CustomItemTouchHelper extends ItemTouchHelper.Callback {

        private RecoverAnimation ra;
        private boolean animatorRunning;
        private boolean swipeBack = false;

    //...

        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)
                {
                    swipeBack = true;
                }
                else
                {
                    swipeBack = false;
                }
                return false;
            }
        });
        }

        @Override
        public int convertToAbsoluteDirection(int flags, int layoutDirection) {
             return swipeBack ? 0 : super.convertToAbsoluteDirection(flags, layoutDirection);
        }

    //...
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32784798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档