RecyclerView每隔几个项目是相同的 - 扩展项

问题描述:

我有一个recyclerView的问题。我正在使用此布局来扩展recyclerView中的cardView:https://github.com/AAkira/ExpandableLayoutRecyclerView每隔几个项目是相同的 - 扩展项

如果我点击某个项目进行展开并且向下滚动,则每第7个元素也会展开。我能做些什么来阻止这种影响?我知道这是由于recyclerView记住了视图持有者的状态并且mIsViewExpanded方法在每个第7项的BindiewHolder设置为true时造成的。预先感谢任何解决方案!

这里是我的viewholder代码:

class EventsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 

    private ImageView edit, cancel, expandIcon; 

    private ExpandableLayout expandableArea; 
    private boolean mIsViewExpanded = false; 

    public EventsViewHolder(View itemView) { 
     super(itemView); 
     expandIcon = (ImageView) itemView.findViewById(R.id.card_item_expand_icon); 
     expandIcon.setOnClickListener(this); 
     //divider = (View) itemView.findViewById(R.id.event_card_divider); 
    } 

    private void collapseArea(){ 
     expandableArea.collapse(); 
     edit.setVisibility(View.GONE); 
     cancel.setVisibility(View.GONE); 
     mIsViewExpanded = false; 
     expandIcon.setImageResource(R.drawable.vector_drawable_ic_expand_more_black___px); 
    } 

    private void expandArea(){ 
     expandableArea.expand(); 
     edit.setVisibility(View.VISIBLE); 
     cancel.setVisibility(View.VISIBLE); 
     mIsViewExpanded = true; 
     expandIcon.setImageResource(R.drawable.vector_drawable_ic_expand_less_black___px); 
    } 

    @Override 
    public void onClick(View view) { 
     if(mIsViewExpanded){ 
      collapseArea(); 
      isItemExpanded[getAdapterPosition()] = false; 
     } 
     else { 
      expandArea(); 
      isItemExpanded[getAdapterPosition()] = true; 
     } 
    } 
} 

当我点击CardView expandableArea里面的图标是扩大还是取决于mIsViewExpanded价值崩溃。

编辑。 适配器代码:

public class EventsRecyclerViewAdapter extends RecyclerView.Adapter<EventsRecyclerViewAdapter.EventsViewHolder> implements PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener { 

public interface EventsRecyclerViewAdapterInterface { 
    public void emptyAdapter(); 

    public void itemDeleted(int id); 
} 

private List<Event> listData = new ArrayList<>(); 
private LayoutInflater inflater; 
private MainActivity context; 
private View view; 
private int positionToCancel; 

private boolean[] isItemExpanded; 

private EventsRecyclerViewAdapterInterface deleteListener; 

@Override 
public boolean onMenuItemClick(MenuItem menuItem) { 
    removeItem(positionToCancel); 
    return true; 
} 

@Override 
public void onDismiss(PopupMenu menu) { 
    menu.dismiss(); 
} 


public EventsRecyclerViewAdapter(Activity context, EventsRecyclerViewAdapterInterface deleteListener) { 
    this.inflater = LayoutInflater.from(context); 
    this.context = (MainActivity) context; 
    this.deleteListener = deleteListener; 
} 

@Override 
public EventsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    view = inflater.inflate(R.layout.item_event_card, parent, false); 
    return new EventsViewHolder(view); 
} 

@Override 
public void onBindViewHolder(EventsViewHolder holder, int position) { 
    Event item = listData.get(position); 

    if(!isItemExpanded[position]){ 
     if(holder.mIsViewExpanded){ 
      holder.collapseArea(); 
     } 
    } 
    else { 
     holder.expandArea(); 
    } 

    holder.title.setText(item.getName()); 
    holder.place.setText(item.getLocation()); 

    DateTimeFormatter formatter = DateTimeFormat.forPattern(StaticValues.DATE_TIME_PATTERN_FOR_VIEW); 
    holder.time.setText(formatter.print(item.getDate())); 

    holder.edit.setOnClickListener(view1 -> takeDetailsEvent(item)); 
    holder.cancel.setOnClickListener(view1 -> { 
     positionToCancel = position; 

     MyPopupMenu popup = new MyPopupMenu(view1.getContext(), view1, context); 
     popup.inflate(R.menu.event_delete_menu); 
     popup.setOnMenuItemClickListener(this); 
     popup.setOnDismissListener(this); 
     popup.show(); 
    }); 

    holder.container.setOnClickListener(view1 -> { 
     Intent intent = new Intent(view1.getContext(), EventDetailsActivity.class); 
     intent.putExtra("eventId", item.getApiId()); 
     view1.getContext().startActivity(intent); 
    }); 
} 

private void removeItem(int position) { 
    deleteListener.itemDeleted(listData.get(position).getApiId()); 
    listData.remove(position); 
    notifyDataSetChanged(); 

    if (getItemCount() == 0) { 
     deleteListener.emptyAdapter(); 
    } 
} 

private void takeDetailsEvent(Event event) { 
    Intent intent = new Intent(view.getContext(), CreateEventActivity.class); 
    intent.putExtra("id", event.getApiId()); 
    view.getContext().startActivity(intent); 
} 

public void setListData(List<Event> eventList) { 
    listData = eventList; 
    isItemExpanded = new boolean[listData.size()]; 
    notifyDataSetChanged(); 
} 

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

}

这是我现在如何处理它。在适配器类中,我有一个布尔数组,它的长度与listData相同。在与列表项目对应的位置上,值为:展开时为true,展开时为false。在onBindViewHolder中,我检查位置是否展开,如果没有,我折叠它。这不是理想的解决方案,因为在滚动项目崩溃时,它看起来不太好。

+0

其中是适配器类? – Rahul

+0

在onBindViewHolder中,在您的适配器中,您可以标准折叠您绑定的ViewHolder。这样,所有新视图都会崩溃。 – Marcel50506

+1

这些项目被回收视图,因此每当您滚动对特定项目的操作时,都会重复其他项目进一步向上或向下列表。你可以做的是使用(.setTag())存储一个项目的动作,并使用(.getTag())进行回放。然后它只是一个例子(如item.getTag()== 1 - 展开其他不扩大)检查关于设置的SO,并获得适配器项目的标签 – Tasos

RecyclerView不会创建新视图,而是在滚动时重新使用现有视图(ScrappedViews)。所以当你扩展CardView并滚动时,发生了什么事情,因为CardView被重用,所以你会得到另一个扩展视图。

因此,只需折叠/展开您的AdapteronBindView()中的视图,因为您需要将状态与适配器列表中的每个项目相关联。

要解决滚动期间展开/折叠动画只需setDuration(0),它允许您展开/折叠没有任何延迟或动画更流畅的滚动体验。

+0

是的我意识到这一点RecyclerView使用ScrappedViews这就是为什么我问我该怎么做。我尝试保存列表中每个项目的状态。我制作了一个布尔数组来记住recyclerview中每个项目的状态。但是当我滚动的时候,在滚动时崩溃的东西很奇怪。此外,当我在每次在onBindViewHolder项目中滚动查看视图时,都会在滚动过程中崩溃,这不是理想的解决方案。 – Zygi

+0

@Zibiksior然后请在你的问题中添加你的“适配器”。 – Abbas

+0

在问题中发布的适配器代码 – Zygi

它是recyclerView的预期行为。 RecyclerView回收不可见的项目。如果您不希望您的物品被回收,请使用holder.setIsRecyclable(false);在你的适配器的onBindViewHolder()方法中。

holder.setIsRecyclable(false); 
+0

使用此解决方案时的性能如何? – Zygi

+0

在这种情况下它应该像listView一样工作。 – saty

+0

我会说这不是一个很好的解决方案,因为@Tasos在注释中提出的'setTag'建议可以解决问题,同时不会影响性能。 – Marcel50506

在您的适配器中覆盖这两种方法。

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

@Override 
public int getItemViewType(int position) { 
return position; 
} 

参考= How to prevent items from getting duplicated when scrolling recycler view