android - 更改和删除的动画不适用于 RecyclerView

标签 android android-animation material-design android-recyclerview

App 有时会从服务器获取更新的数据集,并且需要显示变化的动画。我尝试使用 RecyclerView 和 ItemAnimator,但它不起作用:仅调用了 ItemAnimator 的 animateAdd 方法,没有调用 animateChange 和 animateRemove。

有什么想法不对吗?

我使用 RecyclerView 和数据集更改模拟器制作了简单的应用。

package com.tseglevskiy.recycleviewdevmo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends Activity {

    RecyclerView rv;

    List<DummyData> data;

    Handler handler;

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

        handler = new Handler();

        rv = (RecyclerView)findViewById(R.id.list);
        rv.setItemAnimator(new MyAnimator());

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        layoutManager.scrollToPosition(0);
        rv.setLayoutManager(layoutManager);

        data = new ArrayList<>();
        data.add(new DummyData(1, "foo"));
        data.add(new DummyData(2, "bar"));

        MyAdapter adapter = new MyAdapter(copycopy());
        adapter.setHasStableIds(true);
        rv.setAdapter(adapter);

        loop();
    }

    void loop() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                getNewDataset();
                loop();
            }
        }, 3000);
    }

    List<DummyData> copycopy() {
        List<DummyData> copy = new ArrayList<>();

        for (DummyData f: data) {
            copy.add(new DummyData(f.id, f.what));
        }

        return copy;
    }

    void getNewDataset() {
        long now = System.currentTimeMillis();
        Log.d("foo", "getNewDataset " + now);

        // sometimes remove first
        if (randInt(1, 10) > 7) {
            data.remove(0);
        }
        // remove random
        if (data.size() > 5) {
            data.remove(randInt(data.size()/2, data.size()-1));
        }
        // add a few
        int dummyId = (int)(now % Integer.MAX_VALUE);
        data.add(new DummyData(dummyId, "A" + randInt(0,1000000)));
        data.add(new DummyData(dummyId + 1, "B" + randInt(0, 1000000)));
        data.set(randInt(data.size()/2, data.size()-1),
                new DummyData(dummyId + 2, "C" + randInt(0, 1000000)));

        MyAdapter adapter = new MyAdapter(copycopy());
        adapter.setHasStableIds(true);

        rv.swapAdapter(adapter, false);
    }

    public static int randInt(int min, int max) {
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }

    public static class MyAdapter extends RecyclerView.Adapter<MyHolder> {
        private List<DummyData> items;

        public MyAdapter(List<DummyData> items) {
            this.items = items;
        }

        @Override
        public MyHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false);
            return new MyHolder(v);

        }

        @Override
        public void onBindViewHolder(MyHolder myHolder, int position) {
            DummyData model = items.get(position);
            myHolder.text1.setText(model.what);
        }

        @Override
        public int getItemCount() {
            return items.size();
        }
    }

    public static class MyHolder extends RecyclerView.ViewHolder {
        TextView text1;

        public MyHolder(View itemView) {
            super(itemView);
            text1 = (TextView)itemView.findViewById(android.R.id.text1);
        }
    }

    public static class DummyData {
        public DummyData(int id, String what) {
            this.id = id;
            this.what = what;
        }

        public int id;
        public String what;

        @Override
        public String toString() {
            return what;
        }
    }

    public static class MyAnimator extends DefaultItemAnimator {
        @Override
        public boolean animateAdd(RecyclerView.ViewHolder holder) {
            Log.d("foo", "animateAdd");
            return super.animateAdd(holder);
        }

        @Override
        public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
            Log.d("foo", "animateChange");
            return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
        }

        @Override
        public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
            Log.d("foo", "animateMove");
            return super.animateMove(holder, fromX, fromY, toX, toY);
        }

        @Override
        public boolean animateRemove(RecyclerView.ViewHolder holder) {
            Log.d("foo", "animateRemove");
            return super.animateRemove(holder);
        }
    }
}

最佳答案

无论何时使用 setHasStableIds(true),您都需要覆盖适配器的 getItemId(position) 方法。

它应该返回一个真正唯一的值,而不是position 的直接函数。在您的示例中,它应该是这样的:

@Override
public long getItemId(int position)
{
    return items.get(position).id;
}

当然你还需要在数据更新时调用adapter.notifyDataSetChanged()

关于android - 更改和删除的动画不适用于 RecyclerView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29566719/

相关文章:

android - 为什么键盘出现在 TabBar 之后?

android - 一旦高度为 0,LinearyLayout 将不会调整大小

android - Android 中 Activity 启动时动画 View

java - 在改变 Intent 之前,微调器也会改变它的值

android - 在Android Studio中添加facebook sdk导致 'no resource found'错误

android - AsyncTask.doInBackground - Android Scala 项目中抽象方法未实现错误

android - 知道为什么 Material 设计 "home up"按钮在旋转后会变黑吗?

android - View 立即跳跃和闪烁,虽然 animateLayoutChanges ="true"

android - 将图标+文本添加到 TabLayout

Angularjs Material 一排两列