OnCreateViewHolder is still called even if ItemAni

2019-04-13 07:11发布

I'm building a change animation for my RecyclerView. I've overriden canReuseUpdatedViewHolder() to return true in order to retain the previous viewholder. I start the animation in animateChange() and call dispatchAnimationFinished() as soon as it ends. Params oldHolder and newHolder are the same instance in animateChange().

Then, as soon as the animation starts, RecyclerView's onBindViewHolder() is called for every child in the list. Surprisingly, only for the animated item a new ViewHolder is spawned in onCreateViewHolder() which as I've understood is not the correct behavior. For every other child the old ViewHolder is bound in onBindViewHolder().

As a side note, onBindViewHolder() is called too soon, before the animation is finished. Even if dispatchAnimationFinished(holder) is called after the animation is finished.

Here's the ItemAnimator subclass.

public class CustomItemAnimator extends DefaultItemAnimator {


    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
        return true;
    }

    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) {
        return true;
    }

    @Override
    public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
        CustomHolder holder = (CustomHolder) newHolder;
        CustomView customView = holder.customView;
        Animator animator = customView.revealAnimation();
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                dispatchAnimationFinished(holder);
            }
        });
        animator.start();
        return false;
    }
}

and here's the custom view animation code:

CustomView.java

public Animator revealAnimation() {
    return circularRevealView(visibleView, hiddenView);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private Animator circularRevealView(View visibleView, View invisibleView) {

    // get the center for the clipping circle
    int cx = visibleView.getWidth() / 2;
    int cy = visibleView.getHeight() / 2;

    // get the final radius for the clipping circle
    float finalRadius = (float) Math.hypot(cx, cy);

    // create the animator for this view (the start radius is zero)
    Animator anim =
            ViewAnimationUtils.createCircularReveal(invisibleView, cx, cy, 0, finalRadius);

    visibleView.setVisibility(INVISIBLE);
    invisibleView.setVisibility(View.VISIBLE);

    // return the animation for later use
    return anim;
}

Thanks.

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-04-13 07:23

animateChange(...) is called after notifyDataSetChanged(),it means that onBindViewHolder() goes before animateChange(...).and the state of holder has already changed.maybe you can do it this

animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                visibleView.setVisibility(INVISIBLE);
                invisibleView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                dispatchAnimationFinished(holder);
            }
        });
查看更多
登录 后发表回答