RecyclerView ItemTouchHelper滑动删除动画?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (243)

我在刷卡上有一个删除,它绘制了一个背景(很像收件箱应用程序),由ItemTouchHelper实现 - 通过覆盖onChilDraw方法并在提供的画布上绘制一个矩形:

    ItemTouchHelper mIth = new ItemTouchHelper(
        new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {

            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                remove(viewHolder.getAdapterPosition());
            }

            public boolean onMove(RecyclerView recyclerview, RecyclerView.ViewHolder v, RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

                View itemView = viewHolder.itemView;

                Drawable d = ContextCompat.getDrawable(context, R.drawable.bg_swipe_item_right);
                d.setBounds(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
                d.draw(c);

                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }
        });

上面调用的remove方法在Adapter中:

    public void remove(int position) {
       items.remove(position);
       notifyItemRemoved(position);
    }

背景很好,但是当调用notifyItemRemoved时(根据Debugger先生),RecyclerView首先删除我漂亮的绿色背景,然后将两个相邻的项目推到一起。

我希望它能够保留背景(就像收件箱应用程序一样)。有没有办法做到这一点?

提问于
用户回答回答于

当行动画时回到背景:我无法在内部ItemTouchHelper进行onChildDraw。最后,我不得不添加另一个项目装饰器来做到这一点。它遵循这些方针:

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    if (parent.getItemAnimator().isRunning()) {
        // find first child with translationY > 0
        // draw from it's top to translationY whatever you want

        int top = 0;
        int bottom = 0;

        int childCount = parent.getLayoutManager().getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getLayoutManager().getChildAt(i);
            if (child.getTranslationY() != 0) {
                top = child.getTop();
                bottom = top + (int) child.getTranslationY();                    
                break;
            }
        }

        // draw whatever you want

        super.onDraw(c, parent, state);
    }
}

此代码仅考虑设置动画的行,但您还应考虑下降的行。如果你滑动删除最后一行会发生这种情况,上面的行会动画到该空间。

if (viewHolder.getAdapterPosition() == -1) {
    return;
}

在你的情况下,它是从左= 0到右= 0绘制,所以你没有看到任何东西,但开销就在那里。如果你开始看到之前刷过的行绘制他们的背景,这就是原因。

用户回答回答于

我的ViewHolder现在扩展了库提供的AnimateViewHolder:

    class MyViewHolder extends AnimateViewHolder {

    TextView textView;

    public MyViewHolder(View itemView) {
        super(itemView);
        this.textView = (TextView) itemView.findViewById(R.id.item_name);
    }

    @Override
    public void animateAddImpl(ViewPropertyAnimatorListener listener) {
        ViewCompat.animate(itemView)
                .translationY(0)
                .alpha(1)
                .setDuration(300)
                .setListener(listener)
                .start();
    }

    @Override
    public void preAnimateAddImpl() {
        ViewCompat.setTranslationY(itemView, -itemView.getHeight() * 0.3f);
        ViewCompat.setAlpha(itemView, 0);
    }

    @Override
    public void animateRemoveImpl(ViewPropertyAnimatorListener listener) {
        ViewCompat.animate(itemView)
                .translationY(0)
                .alpha(1)
                .setDuration(300)
                .setListener(listener)
                .start();
    }

}

覆盖的函数实现与github上的recyclerview-animators自述文件相同。

似乎有必要将ItemAnimator更改为自定义,并将removeDuration设置为0(或另一个低值 - 这是为了防止一些闪烁):

    recyclerView.setItemAnimator(new SlideInLeftAnimator());
    recyclerView.getItemAnimator().setRemoveDuration(0);

原来ItemTouchHelper.SimpleCallback使用ItemAnimator的动画持续时间,这就是上面的setRemoveDuration(0)打破滑动动画的原因。简单地将它的方法getAnimationDuration覆盖为:

@Override
public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
    return animationType == ItemTouchHelper.ANIMATION_TYPE_DRAG ? DEFAULT_DRAG_ANIMATION_DURATION
            : DEFAULT_SWIPE_ANIMATION_DURATION;
}

解决了这个问题。

所属标签

可能回答问题的人

  • 嗨喽你好

    7 粉丝480 提问9 回答
  • uncle_light

    5 粉丝518 提问8 回答
  • 富有想象力的人

    3 粉丝0 提问7 回答
  • 无聊至极

    4 粉丝504 提问6 回答

扫码关注云+社区

领取腾讯云代金券