Android RecyclerView动画问题

12

我正在尝试在recyclerview中制作可扩展的cardviews。我已经实现了展开部分,但是当添加过渡动画时,一些视觉错误开始出现。过渡效果在没有屏幕外物品的情况下运行良好,但是当我向recyclerview添加超过(在我的情况下)4个项目时,它开始出现问题。

具有4个项目的GIF

超过4个项目的GIF

当我禁用过渡动画时,可以使用超过4个项目正常工作。我认为问题与位置的更改有关,但我找不到解决问题的方法。

我用来实现cardview展开的指南可以在此处找到:https://dev59.com/aF4d5IYBdhLWcg3wE_KP#38623873

以下是我的完整recyclerview适配器:

public class BasketRecyclerAdapter extends RecyclerView.Adapter<BasketRecyclerAdapter.CustomViewHolder> {
private String letter;
private Context mContext;
private ColorGenerator generator = ColorGenerator.MATERIAL;
private List<Basket> baskets;
private int mExpandedPosition = -1;
private RecyclerView r1;

public BasketRecyclerAdapter(Context context, List<Basket> baskets, RecyclerView r1) {
    this.mContext = context;
    this.baskets = baskets;
    this.r1 = r1;

}

@Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.basket_menu_item, null);
    CustomViewHolder viewHolder = new CustomViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(final BasketRecyclerAdapter.CustomViewHolder holder, final int position) {

    String basketName = baskets.get(position).getBasketName();

    holder.basketName.setText(basketName);

    letter = "" + basketName.charAt(0);

    TextDrawable drawable = TextDrawable.builder()
            .buildRound(letter, generator.getColor(basketName));


    holder.imageLetter.setImageDrawable(drawable);

    final boolean isExpanded = position == mExpandedPosition;
    holder.expandedLayout.setVisibility(isExpanded?View.VISIBLE:View.GONE);
    holder.itemView.setActivated(isExpanded);
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mExpandedPosition = isExpanded ? -1:position;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                TransitionManager.beginDelayedTransition(r1);
            }
            notifyDataSetChanged();
        }
    });


}

有什么方法可以解决这个问题吗?谢谢。

编辑:我尝试仅使用ListView而不是RecyclerView来使其正常工作,但ListView适配器使用相同的代码无法展开 - 我将尝试弄清楚为什么。

编辑2:通过使用另一个名为“ExpandableLayout”的库使其正常工作,但似乎仍然无法弄清楚为什么不能在没有其他库的情况下工作。


考虑将 TransitionManager.beginDelayedTransition(r1); 更改为 **TransitionManager.beginDelayedTransition(<列表项的ViewGroup>);**。 - Vishnu T B
我使用TransitionManager,但是当在RecyclerView中关闭动画时,先前的项目会在动画实际完成之前堆积起来。 - Sasmita
3个回答

4

我有类似的问题。 在适配器中添加:

@Override
public long getItemId(int position) {
    return position;
}

And myAdapter.setHasStableIds(true);


4

我曾经遇到过同样的问题。这是我解决问题的方法,并且像你在GIF with 4 items中展示的那样运行:)

在你的自定义适配器中,添加notifyItemChanged(position)notifyItemChanged(previousExpandedPosition)而不是notifyDataSetChanged()

public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
    final boolean isExpanded = position==mExpandedPosition;

    holder.expandedLayout.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
    holder.itemView.setActivated(isExpanded);

    if (isExpanded)
        mPreviousExpandedPosition = position;

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mExpandedPosition = isExpanded ? -1:position;
            TransitionManager.beginDelayedTransition(mRecyclerView);

            notifyItemChanged(mPreviousExpandedPosition);
            notifyItemChanged(position);
        }
    });
}

声明全局变量mExpandedPositionmPreviousExpandedPosition,并将它们初始化为-1。

mRecyclerView作为参数传递给适配器的构造函数。

在片段或活动中,在为回收视图设置适配器后,设置mRecyclerView.setItemAnimator(null),就像这样:

mRecyclerView.setAdapter(mRecyclerViewAdapter);
mRecyclerView.setItemAnimator(null);

这应该可以解决你的问题。

1
非常感谢。它解决了我的问题。如果没有给出mRecyclerView.setItemAnimator(null);,默认的淡出效果会发生... - Monster Brain
1
我已经花了3个小时来解决这个问题。非常感谢你。 - Roach

2

我遇到了类似的问题。当没有屏幕外的项目时,它可以正常工作,但是当您有屏幕外的项目时,动画无法正常工作。解决方案是不要使用notifyDataSetChanged()更新适配器中的每个项目。您需要仅更新要展开的位置和要折叠的位置。我猜测屏幕外的项目的ViewHolders会影响动画。

    final boolean isExpanded = position == mExpandedPosition;
    vh.expandableView.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
    vh.itemView.setActivated(isExpanded);
    vh.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            // collapse any currently expanded items
            if (mExpandedPosition != RecyclerView.NO_POSITION) {
                notifyItemChanged(mExpandedPosition);
            }

            //Update expanded position
            mExpandedPosition = isExpanded ? -1 : position;

            TransitionManager.beginDelayedTransition(mRecyclerView);

            //Expand new item clicked
            notifyItemChanged(position);

        }
    });

哎呀,我找了好久才找到这个。这个解决方案并不完美,因为更改的项目仍然会淡出和重新出现,但它确实有效。很烦人的是,它对于屏幕上没有的视图完美地工作。另外,如果oldPosition != -1,请不要忘记通知notifyItemChanged(oldPosition)。 - easycheese

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接