【问题标题】:Recycler View add Item Animator not animatingRecyclerview添加项目动画不动画
【发布时间】:2020-11-02 20:24:56
【问题描述】:

我正在尝试使用自定义项目动画器在单击按钮后为项目视图设置动画。单击添加按钮后,新项目出现,但没有发生所需的动画。它只是突然出现。我已经尝试了所有方法,请帮助。

viewholder_add_anim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration = "500"
        android:fromXScale="0%"
        android:fromYScale="0%"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="100%"
        android:toYScale="100%"/>
</set>

CustomItemAnimator

import android.view.animation.AnimationUtils;

import com.example.bookui.R;

import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;

public class CustomItemAnimator extends DefaultItemAnimator {
    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        return super.animateRemove(holder);
    }

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        holder.itemView.setAnimation(AnimationUtils.loadAnimation(holder.itemView.getContext(), 
                R.anim.viewholder_add_anim));
        return super.animateAdd(holder);
    }
}

主要活动 公共类 MainActivity 扩展 AppCompatActivity {

    private RecyclerView recyclerViewBooks;
    private BookAdapter bookAdapter;
    private List<Book> mdata;
    private Button addButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        initmdataBooks();
        setUpBookAdapter();
    }

    private void initViews() {
        addButton = findViewById(R.id.add_btn);
        recyclerViewBooks = findViewById(R.id.recyclerView);
        recyclerViewBooks.setHasFixedSize(true);

        recyclerViewBooks.setItemAnimator(new CustomItemAnimator());

        addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                addBook();
            }
        });
    }

    private void initmdataBooks() {
        mdata = new ArrayList<>();
        mdata.add(new Book(R.drawable.book1));
        mdata.add(new Book(R.drawable.book2));
        mdata.add(new Book(R.drawable.book3));
        mdata.add(new Book(R.drawable.book2));
        mdata.add(new Book(R.drawable.book4));
        mdata.add(new Book(R.drawable.book5));
        mdata.add(new Book(R.drawable.book1));
        mdata.add(new Book(R.drawable.book1));
        mdata.add(new Book(R.drawable.book5));
    }

    private void setUpBookAdapter() {
        bookAdapter = new BookAdapter(mdata);
        recyclerViewBooks.setAdapter(bookAdapter);
    }

    private void addBook() {
        Book book = new Book(R.drawable.book4);
        mdata.add(1, book);
        bookAdapter.notifyDataSetChanged();
    }
}

【问题讨论】:

    标签: android android-studio animation android-recyclerview android-animation


    【解决方案1】:

    你必须正确地履行ItemAnimator合约,而不是盲目地覆盖animateAdd

    1. 不要拨打super.animateAdd(holder) - 你只会与默认的淡入动画冲突。
    2. 您必须跟踪此动画并调用dispatchAddStarting(holder) / dispatchAddFinished(holder) 通知超级实现当前动画状态。
    3. 您必须重写几个必须知道您的动画是否正在运行并提供取消选项的方法(在下面的代码中)

    覆盖DefaultItemAnimator 示例以在新添加的项目上运行放大动画:

    public class AddRecAnimator extends DefaultItemAnimator {
        private final static String TAG = "AddRecAnimator";
    
        // must keep track of all pending/ongoing animations.
        private final ArrayList<AddHolder> pending = new ArrayList<>();
        private final HashMap<RecyclerView.ViewHolder, AddHolder> additions = new HashMap<>();
    
        @Override
        public boolean animateAdd(RecyclerView.ViewHolder holder) {
            pending.add(new AddHolder(holder));
            return true;    // return true to receive call to runPendingAnimations
        }
    
        @Override
        public void runPendingAnimations() {
            for (AddHolder ah : pending) {
                ah.start();
            }
            pending.clear();
            super.runPendingAnimations();
        }
    
        @Override
        public void endAnimation(RecyclerView.ViewHolder item) {
            AddHolder ah = additions.get(item);
            if (ah != null) {
                ah.endAnimation();
            }
            super.endAnimation(item);
        }
    
        @Override
        public void endAnimations() {
            for (AddHolder ah : pending) {
                ah.resetViewHolderState();
                dispatchAddFinished(ah.holder);
            }
            for (AddHolder ah : additions.values()) {
                ah.resetViewHolderState();
                dispatchAddFinished(ah.holder);
            }
            pending.clear();
            additions.clear();
            super.endAnimations();
        }
    
        @Override
        public boolean isRunning() {
            return super.isRunning() &&
                    !pending.isEmpty() &&
                    !additions.isEmpty();
        }
    
        /**
         * This is container for addition animation. It's also end listener for it.
         */
        private final class AddHolder implements Animation.AnimationListener {
            private final RecyclerView.ViewHolder holder;
    
            private AddHolder(RecyclerView.ViewHolder holder) {
                this.holder = holder;
                Animation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f,
                        ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                        ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
                anim.setDuration(500);
                anim.setAnimationListener(this);
                holder.itemView.setAnimation(anim);
                dispatchAddStarting(holder);
            }
    
            void start() {
                View itemView = holder.itemView;
                Animation a = itemView.getAnimation();
                if (a != null) {
                    a.start();
                    additions.put(holder, this);
                } else {
                    endAnimation(); // invalid state, animation missing
                }
            }
    
            private void resetViewHolderState() {
                // reset state as if no animation was ran
                Animation a = holder.itemView.getAnimation();
                if (a != null) {
                    a.setAnimationListener(null);
                    a.cancel();
                    holder.itemView.clearAnimation();
                }
                holder.itemView.setScaleX(1f);
                holder.itemView.setScaleY(1f);
            }
    
            // called when animation ends or is manually cancelled
            protected void endAnimation(){
                additions.remove(holder);
                resetViewHolderState();
                dispatchAddFinished(holder);
                // if all animations in animator are done dispatch they're finished
                if (!isRunning()) dispatchAnimationsFinished();
            }
    
            @Override
            public void onAnimationStart(Animation animation) {
    
            }
    
            @Override
            public void onAnimationEnd(Animation animation) {
                endAnimation();
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
    
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-05
      • 2019-04-12
      • 1970-01-01
      • 1970-01-01
      • 2015-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多