使用DefaultItemAnimator时,StaggeredGridLayoutManager的移动动画已损坏 [英] Move animation for StaggeredGridLayoutManager is broken when using DefaultItemAnimator

查看:111
本文介绍了使用DefaultItemAnimator时,StaggeredGridLayoutManager的移动动画已损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 StaggeredGridLayoutManager 进行了非常简单的实现.

我想基于 DefaultItemAnimator

实现移动动画

将第3项切换为第4项

如下面的屏幕记录所示,我尝试将第3项切换为第4项.效果很好.动画只涉及第三和第四项.

将第一项与第二项切换

但是,当我尝试将第一项与第二项切换时,该行为被某种程度破坏了.

我希望动画仅发生在第一项和第二项之间.但是,即使每个项目的宽度和高度都相同,整个列表似乎也正在被动画化.(因此,不应执行任何间隙填充操作)

每次切换后,您需要滚动 RecyclerView ,以使切换后的项目可见.


我尝试过的东西

  1. 使用

      staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE); 

    将无济于事.

为了知道幕后发生的事情,我尝试在日志记录中使用以下 DefaultItemAnimator .

 公共类DebugDefaultItemAnimator扩展DefaultItemAnimator {@Override公共布尔animateRemove(RecyclerView.ViewHolder持有人){Log.i("CHEOK","animateRemove");返回super.animateRemove(holder);}@Override公共布尔animateAdd(RecyclerView.ViewHolder持有人){Log.i("CHEOK","animateAdd");返回super.animateAdd(holder);}@Override公共布尔animateMove(RecyclerView.ViewHolder持有者,int fromX,int fromY,int toX,int toY){Log.i("CHEOK","animateMove(" + fromX +," + fromY +)到(" + toX +," + toY +)");返回super.animateMove(holder,fromX,fromY,toX,toY);}@Overridepublic boolean animateChange(RecyclerView.ViewHolder oldHolder,RecyclerView.ViewHolder newHolder,int fromLeft,int fromTop,int toLeft,int toTop){Log.i("CHEOK","animateChange");返回super.animateChange(oldHolder,newHolder,fromLeft,fromTop,toLeft,toTop);}} 

当我们在第三和第四之间切换时,一切正常,这是日志.

  animateMove(24,250)至(564,250)动画(564,250)至(24,250) 

但是当我们在第一项和第二项之间切换时,情况就坏了,这是日志.

  animateMove(24,928)至(564,702)动画(564,476)至(24,476)animate从(24,1154)移至(564,928)动画(24,476)至(564,250)动画(564,1154)至(24,1154)动画(564,250)至(24,250)动画(564,702)至(24,702)动画(564,928)至(24,928)动画删除动画(24,702)至(564,476)动画(24,1380)移至(564,1154)动画(24,250)至(564,24)动画添加动画(564,1380)移至(24,1380) 


我的实现非常简单

任何想法可能出什么问题吗?我尝试将 StaggeredGridLayoutManager 替换为 LinearLayoutManager GridLayoutManager .除 StaggeredGridLayoutManager 之外,其他所有方法均正常运行.

源代码如下.(可以从

如您所见,起初一切都按预期工作:当屏幕不满时,项目会移动,动画也应保持原样.但是,当我们添加项目"M"时,一切都会如您所愿.我的结论是,这是一个错误.它看起来像是与间隙管理相关的边界问题,但这只是我的猜测.

我已进一步确认这是一个布局问题,可以证明虽然 RecyclerView 的子代顺序正确,但 StaggeredGridLayout 失败以相同的顺序布置子项.滚动时,您将迫使布局管理器重新查看布局,尽管适配器没有任何更改,但布局仍正确无误.

我要补充一点,这不是项目动画师的问题.如果您将动画设置为关闭( recyclerView.setItemAnimator(null); ),问题仍然存在.

一种解决方法是自定义 ListUpdateCallback 来捕获问题情况并采取其他措施.在下面的代码中, MyListUpdateCallback onMoved()方法寻找到位置0的移动,并从到位置调用 notifyItemChanged ;否则,处理将照常进行.

以下是应用了修复程序的应用程序:

尽管此解决方案可以解决您提供的MCVE的问题,但可能无法完全按照书面要求解决实际应用中的问题.如果没有,我相信可以采用这种方法.

MainActivity.java

这是演示的更新代码.将布尔值 mDoTheFix 设置为true即可应用此修复程序.如果 mDoTheFix 为false,则该应用程序将表现出损坏的行为.

 公共类MainActivity扩展了AppCompatActivity实现的View.OnClickListener {私人RecyclerView recyclerView;私有列表<数据>数据=新的ArrayList<>();专用适配器适配器;@Override受保护的void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);recyclerView = findViewById(R.id.recycler_view);StaggeredGridLayoutManager staggeredGridLayoutManager =新的StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL){@Overridepublic void onLayoutCompleted(RecyclerView.State状态){//super.onLayoutCompleted(state);}};//recyclerView.setItemAnimator(null);//staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);this.recyclerView.setLayoutManager(staggeredGridLayoutManager);datas.add(new Data(0,"A title","A body"));datas.add(new Data(1,"B标题","B正文"));datas.add(new Data(2,"C标题","C主体"));datas.add(new Data(3,"D标题","D主体"));datas.add(new Data(4,"E标题","E主体"));datas.add(new Data(5,"F标题","F主体"));datas.add(new Data(6,"G标题","G主体"));datas.add(new Data(7,"H title","H body"));datas.add(new Data(8,"I title","I body"));datas.add(new Data(9,"J标题","J主体"));datas.add(new Data(10,"K标题","K主体"));datas.add(new Data(11,"L title","L body"));datas.add(new Data(12,"M title","M body"));//datas.add(new Data(13,"N title","N body")));//datas.add(new Data(14,"O title","O body")));//datas.add(new Data(11,"P title","P body")));//datas.add(new Data(12,"Q title","Q body")));//datas.add(new Data(13,"R title","R body")));//datas.add(new Data(14,"S title","S body")));adapter = new Adapter(datas,this);recyclerView.setAdapter(adapter);}@Overridepublic boolean onCreateOptionsMenu(Menu menu){MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.menu,菜单);返回true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item){//处理项目选择开关(item.getItemId()){案例R.id.debug:{字符串s =(字符串)((TextView)((((LinearLayout)((FrameLayout)recyclerView.getChildAt(0)).getChildAt(0)).getChildAt(0))).getText();数据data0 = datas.get(0);数据data1 = datas.get(1);datas.set(0,data1);datas.set(1,data0);新的MyListUpdateCallback().onMoved(1,0);返回true;}案例R.id.debug2:数据data2 = datas.get(2);数据data3 = datas.get(3);datas.set(2,data3);datas.set(3,data2);adapter.notifyItemMoved(2,3);返回true;案例R.id.debug3:{列表<数据>oldDatas = new ArrayList(数据);数据data0 = datas.get(0);数据data1 = datas.get(1);datas.set(0,data1);datas.set(1,data0);MyNoteDiffUtilCallback noteDiffUtilCallback =新的MyNoteDiffUtilCallback(数据,oldDatas);DiffUtil.calculateDiff(noteDiffUtilCallback).dispatchUpdatesTo(new MyListUpdateCallback());返回true;}案例R.id.debug4:字符串ABC ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";int i = datas.size();如果(i< 26){字符串ch = ABC.substring(i,i + 1);datas.add(new Data(12,ch +"title",ch +"body"));adapter.notifyItemInserted(i-1);}返回true;案例R.id.debug5:int toRemove = datas.size()-1;datas.remove(toRemove);adapter.notifyItemRemoved(toRemove);返回true;默认:返回super.onOptionsItemSelected(item);}}@Overridepublic void onClick(View v){int oldPos = recyclerView.getLayoutManager().getPosition(v);int newPos = oldPos-1;如果(newPos< 0){返回;}数据data0 = datas.get(oldPos);数据data1 = datas.get(newPos);datas.set(oldPos,data1);datas.set(newPos,data0);new MyListUpdateCallback().onMoved(oldPos,newPos);}公共类MyNoteDiffUtilCallback扩展了DiffUtil.Callback {私有列表<数据>newsDatas;私有列表<数据>oldDatas;公共MyNoteDiffUtilCallback(List< Data> newsDatas,List< Data> oldDatas){this.newsDatas = newsDatas;this.oldDatas = oldDatas;}@Overridepublic int getOldListSize(){返回oldDatas.size();}@Overridepublic int getNewListSize(){返回newsDatas.size();}@Overridepublic boolean areItemsTheSame(int oldItemPosition,int newItemPosition){返回oldDatas.get(oldItemPosition).id == newsDatas.get(newItemPosition).id;}@Overridepublic boolean areContentsTheSame(int oldItemPosition,int newItemPosition){返回oldDatas.get(oldItemPosition).equals(newsDatas.get(newItemPosition));}}布尔值mDoTheFix = true;私有类MyListUpdateCallback实现ListUpdateCallback {@Overridepublic void onMoved(int fromPosition,int toPosition){if(mDoTheFix&& toPosition == 0){adapter.notifyItemChanged(fromPosition);adapter.notifyItemChanged(toPosition);} 别的 {adapter.notifyItemMoved(fromPosition,toPosition);}}public void onInserted(int position,int count){adapter.notifyItemRangeInserted(position,count);}@Overridepublic void onRemoved(int position,int count){adapter.notifyItemRangeRemoved(position,count);}@Overridepublic void onChanged(int position,int count,对象有效载荷){adapter.notifyItemRangeChanged(位置,计数,有效载荷);}}} 

menu.xml

 <菜单xmlns:android ="http://schemas.android.com/apk/res/android"xmlns:myApp ="http://schemas.android.com/apk/res-auto">< item android:id ="@ + id/debug"android:title ="0-> 1"myApp:showAsAction ="always"/>< item android:id ="@ + id/debug2"android:title ="2-> 3"myApp:showAsAction ="always"/>< item android:id ="@ + id/debug3"android:title ="DiffUtil"myApp:showAsAction ="always"/>< item android:id ="@ + id/debug4"android:title =添加"myApp:showAsAction ="always"/>< item android:id ="@ + id/debug5"android:title ="Del"myApp:showAsAction ="always"/></菜单> 

I have a very straight forward implementation using StaggeredGridLayoutManager.

I want to achieve move animation based on DefaultItemAnimator

Switch 3rd item with 4th item

I try to switch 3rd item with 4th item as you can see in the following screen record. It works pretty well. Animation only involves 3rd and 4th item.

Switch 1st item with 2nd item

However, when I try to switch 1st item with 2nd item, the behavior is somehow broken.

I expect animation only happen between 1st item and 2nd item. However, it seems that the entire list is being animated, even though every item is having same width and height. (Hence, no gap filling action should be performed)

Everytime, after the switching, you need to scroll the RecyclerView, in order for the switched item to be visible.


What I had tried out

  1. Use

    staggeredGridLayoutManager.setGapStrategy( StaggeredGridLayoutManager.GAP_HANDLING_NONE); 
    

    will not help.

In order to know what happens behind the scene, I try to use the following DefaultItemAnimator with logging.

public class DebugDefaultItemAnimator extends DefaultItemAnimator {
    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        Log.i("CHEOK", "animateRemove");
        return super.animateRemove(holder);
    }

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        Log.i("CHEOK", "animateAdd");
        return super.animateAdd(holder);

    }

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

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
        Log.i("CHEOK", "animateChange");
        return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop);
    }
}

When we switch between 3rd and 4th, everything is OK and here's the logs.

animateMove (24,250) to (564,250)
animateMove (564,250) to (24,250)

But when we switch between 1st item and 2nd item, things are broken and here's the log.

animateMove (24,928) to (564,702)
animateMove (564,476) to (24,476)
animateMove (24,1154) to (564,928)
animateMove (24,476) to (564,250)
animateMove (564,1154) to (24,1154)
animateMove (564,250) to (24,250)
animateMove (564,702) to (24,702)
animateMove (564,928) to (24,928)
animateRemove
animateMove (24,702) to (564,476)
animateMove (24,1380) to (564,1154)
animateMove (24,250) to (564,24)
animateAdd
animateMove (564,1380) to (24,1380)


My implementation is very straight forward.

Any idea what could went wrong? I try to replace StaggeredGridLayoutManager with LinearLayoutManager and GridLayoutManager. All works well except for StaggeredGridLayoutManager.

The source code is as follow. (The complete source code can be downloaded from https://github.com/yccheok/StaggeredGridLayoutManagerProblem)


Adapter.java

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {

    private List<Data> datas;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public final TextView titleTextView;
        public final TextView bodyTextView;
        public ViewHolder(View view) {
            super(view);

            titleTextView = view.findViewById(R.id.title_text_view);
            bodyTextView = view.findViewById(R.id.body_text_view);
        }
    }

    public Adapter(List<Data> datas) {
        this.datas = datas;

        setHasStableIds(true);
    }

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

    public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item, parent, false);

        ViewHolder vh = new ViewHolder(view);
        return vh;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.titleTextView.setText(datas.get(position).title);
        holder.bodyTextView.setText(datas.get(position).body);

    }

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

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;

    private List<Data> datas = new ArrayList<>();
    private Adapter adapter;

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

        recyclerView = findViewById(R.id.recycler_view);

        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);

        //staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);

        this.recyclerView.setLayoutManager(staggeredGridLayoutManager);

        datas.add(new Data(0, "A title", "A body"));
        datas.add(new Data(1, "B title", "B body"));
        datas.add(new Data(2, "C title", "C body"));
        datas.add(new Data(3, "D title", "D body"));
        datas.add(new Data(4, "E title", "E body"));
        datas.add(new Data(5, "F title", "F body"));
        datas.add(new Data(6, "G title", "G body"));
        datas.add(new Data(7, "H title", "H body"));
        datas.add(new Data(8, "I title", "I body"));
        datas.add(new Data(9, "J title", "J body"));
        datas.add(new Data(10, "K title", "K body"));
        datas.add(new Data(11, "L title", "L body"));
        datas.add(new Data(12, "M title", "M body"));
        datas.add(new Data(13, "N title", "N body"));
        datas.add(new Data(14, "O title", "O body"));
        adapter = new Adapter(datas);

        recyclerView.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.debug:

                Data data0 = datas.get(0);
                Data data1 = datas.get(1);

                datas.set(0, data1);
                datas.set(1, data0);

                adapter.notifyItemMoved(0, 1);

                return true;

            case R.id.debug2:

                Data data2 = datas.get(2);
                Data data3 = datas.get(3);

                datas.set(2, data3);
                datas.set(3, data2);

                adapter.notifyItemMoved(2, 3);

                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

Data.java

public class Data {
    public final int id;
    public final String title;
    public final String body;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Data data = (Data) o;

        if (id != data.id) return false;
        if (title != null ? !title.equals(data.title) : data.title != null) return false;
        return body != null ? body.equals(data.body) : data.body == null;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (title != null ? title.hashCode() : 0);
        result = 31 * result + (body != null ? body.hashCode() : 0);
        return result;
    }

    public Data(int id, String title, String body) {

        this.id = id;
        this.title = title;
        this.body = body;
    }
}


Important Note

Please don't suggest using notifyItemRangeChanged or notifyItemChanged. As, this is a "move" operation, not "change" operation.

If you use DiffUtil for the above case, notifyItemMoved will definitely be fired.

I already updated the code in GitHub, to prove DiffUtil will fire notifyItemMoved. Hence, DiffUtil will fail too as far as animation is concern - https://github.com/yccheok/StaggeredGridLayoutManagerProblem/commit/cfa2bc9659f11e52dcee97ce8e78dcfcb6ad5e8c

I'm more interested to know why notifyItemMoved doesn't work for the above case, and how to make it work.


Conclusion

I filed a bug report in https://issuetracker.google.com/issues/78373192 . Please star it if you would like to see it to be solved.

解决方案

This looks like a bug in StaggeredGridLayoutManager. I have taken your app and made a few modifications to it for the following demo. Consider the following that makes this point:

As you can see, initially everything works as expected: Items move and the animations are as they should be when the screen is not full. However, when we add item "M", everything goes haywire as you have presented. My conclusion is that this is a bug. It looks like a boundary problem related to gap management but that is just my guess.

I have further confirmed this as a layout issue and can demonstrate that while the order of the children of the RecyclerView is correct, StaggeredGridLayout fails to layout the children in the same order. When you scroll, you are forcing the layout manager to take another look at the layout and then it gets it right although there are no changes to the adapter.

I will add that this is not an issue with the item animator. If you set the animation off (recyclerView.setItemAnimator(null);) the problem persists.

One workaround is to customize ListUpdateCallback to capture the problem situation and do something different. In the code below, the onMoved() method of MyListUpdateCallback looks for a move to position 0 and call notifyItemChanged on the from the to positions; otherwise, processing proceeds as normal.

Here is the app with the fix applied:

While this solution addresses the issues with the MCVE that you offered, it may not address the issue in the real app exactly as written. If it doesn't, I believe that this approach can be adapted to work.

MainActivity.java

This is the updated code for the demo. Set the boolean mDoTheFix to true to apply the fix. If mDoTheFix is false, the app will exhibit the broken behavior.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private RecyclerView recyclerView;

    private List<Data> datas = new ArrayList<>();
    private Adapter adapter;

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

        recyclerView = findViewById(R.id.recycler_view);

        StaggeredGridLayoutManager staggeredGridLayoutManager =
            new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) {
                @Override
                public void onLayoutCompleted(RecyclerView.State state) {
//                    super.onLayoutCompleted(state);
                }
            };
        //        recyclerView.setItemAnimator(null);
//        staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
        this.recyclerView.setLayoutManager(staggeredGridLayoutManager);
        datas.add(new Data(0, "A title", "A body"));
        datas.add(new Data(1, "B title", "B body"));
        datas.add(new Data(2, "C title", "C body"));
        datas.add(new Data(3, "D title", "D body"));
        datas.add(new Data(4, "E title", "E body"));
        datas.add(new Data(5, "F title", "F body"));
        datas.add(new Data(6, "G title", "G body"));
        datas.add(new Data(7, "H title", "H body"));
        datas.add(new Data(8, "I title", "I body"));
        datas.add(new Data(9, "J title", "J body"));
        datas.add(new Data(10, "K title", "K body"));
        datas.add(new Data(11, "L title", "L body"));
        datas.add(new Data(12, "M title", "M body"));
//        datas.add(new Data(13, "N title", "N body"));
//        datas.add(new Data(14, "O title", "O body"));
//        datas.add(new Data(11, "P title", "P body"));
//        datas.add(new Data(12, "Q title", "Q body"));
//        datas.add(new Data(13, "R title", "R body"));
//        datas.add(new Data(14, "S title", "S body"));
        adapter = new Adapter(datas, this);

        recyclerView.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.debug: {
                String s = (String) ((TextView) (((LinearLayout) ((FrameLayout) recyclerView.getChildAt(0)).getChildAt(0)).getChildAt(0)))
                    .getText();
                Data data0 = datas.get(0);
                Data data1 = datas.get(1);

                datas.set(0, data1);
                datas.set(1, data0);

                new MyListUpdateCallback().onMoved(1, 0);

                return true;
            }

            case R.id.debug2:

                Data data2 = datas.get(2);
                Data data3 = datas.get(3);

                datas.set(2, data3);
                datas.set(3, data2);

                adapter.notifyItemMoved(2, 3);

                return true;

            case R.id.debug3: {
                List<Data> oldDatas = new ArrayList<>(datas);

                Data data0 = datas.get(0);
                Data data1 = datas.get(1);

                datas.set(0, data1);
                datas.set(1, data0);

                MyNoteDiffUtilCallback noteDiffUtilCallback = new MyNoteDiffUtilCallback(datas, oldDatas);
                DiffUtil.calculateDiff(noteDiffUtilCallback).dispatchUpdatesTo(new MyListUpdateCallback());

                return true;
            }

            case R.id.debug4:
                String ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                int i = datas.size();
                if (i < 26) {
                    String ch = ABC.substring(i, i + 1);
                    datas.add(new Data(12, ch + " title", ch + " body"));
                    adapter.notifyItemInserted(i - 1);
                }
                return true;

            case R.id.debug5:
                int toRemove = datas.size() - 1;
                datas.remove(toRemove);
                adapter.notifyItemRemoved(toRemove);
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onClick(View v) {
        int oldPos = recyclerView.getLayoutManager().getPosition(v);
        int newPos = oldPos - 1;
        if (newPos < 0) {
            return;
        }
        Data data0 = datas.get(oldPos);
        Data data1 = datas.get(newPos);

        datas.set(oldPos, data1);
        datas.set(newPos, data0);
        new MyListUpdateCallback().onMoved(oldPos, newPos);
    }

    public class MyNoteDiffUtilCallback extends DiffUtil.Callback {
        private List<Data> newsDatas;
        private List<Data> oldDatas;


        public MyNoteDiffUtilCallback(List<Data> newsDatas, List<Data> oldDatas) {
            this.newsDatas = newsDatas;
            this.oldDatas = oldDatas;
        }

        @Override
        public int getOldListSize() {
            return oldDatas.size();
        }

        @Override
        public int getNewListSize() {
            return newsDatas.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return oldDatas.get(oldItemPosition).id == newsDatas.get(newItemPosition).id;
        }

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            return oldDatas.get(oldItemPosition).equals(newsDatas.get(newItemPosition));
        }
    }

    boolean mDoTheFix = true;

    private class MyListUpdateCallback implements ListUpdateCallback {

        @Override
        public void onMoved(int fromPosition, int toPosition) {
            if (mDoTheFix && toPosition == 0) {
                adapter.notifyItemChanged(fromPosition);
                adapter.notifyItemChanged(toPosition);
            } else {
                adapter.notifyItemMoved(fromPosition, toPosition);
            }
        }

        public void onInserted(int position, int count) {
            adapter.notifyItemRangeInserted(position, count);
        }

        @Override
        public void onRemoved(int position, int count) {
            adapter.notifyItemRangeRemoved(position, count);
        }

        @Override
        public void onChanged(int position, int count, Object payload) {
            adapter.notifyItemRangeChanged(position, count, payload);
        }
    }
}

menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myApp="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/debug"
        android:title="0->1"
        myApp:showAsAction="always" />

    <item android:id="@+id/debug2"
        android:title="2->3"
        myApp:showAsAction="always" />

    <item android:id="@+id/debug3"
        android:title="DiffUtil"
        myApp:showAsAction="always" />

    <item android:id="@+id/debug4"
        android:title="Add"
        myApp:showAsAction="always" />

    <item android:id="@+id/debug5"
        android:title="Del"
        myApp:showAsAction="always" />
</menu>

这篇关于使用DefaultItemAnimator时,StaggeredGridLayoutManager的移动动画已损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆