更改和删除的动画不适用于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)方法.
它应该返回一个真正唯一的值,而不是仓位的直接函数.在您的示例中,它应该类似于:
@Override
public long getItemId(int position)
{
return items.get(position).id;
}
当然,您还需要在数据更新时调用adapter.notifyDataSetChanged()
标签:android-recyclerview,material-design,android-animation,android 来源: https://codeday.me/bug/20191120/2044460.html