2016-08-23 3 views
3

У меня проблема с recyclerView. Я использую этот макет для расширения cardView в recyclerView: https://github.com/AAkira/ExpandableLayout.RecyclerView каждые несколько элементов одинаковы - расширяемый элемент

Если я нажимаю на какой-либо элемент, который нужно развернуть, а затем прокрутка вниз, каждый 7-й элемент также будет расширен. Что я могу сделать, чтобы остановить этот эффект? Я знаю, что это вызвано beacause recyclerView запоминает состояние держателя вида и mIsViewExpanded в методе onBindiewHolder устанавливается равным true для каждого 7-го элемента. Заранее благодарим за любые решения!

Вот код моего 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.

EDIT. Adapter Код:

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 - Expand else Dont expand) проверьте SO о наборе и получите тег для элементов адаптера – Tasos

ответ

2

RecyclerView не создает новые виды вместо того, чтобы повторно использовать существующие виды при прокрутке (ScrappedViews). Так что происходит, когда вы расширяете CardView и прокручиваете, так как повторно используются CardView s, вы получаете еще один расширенный вид.

Так просто свернуть/развернуть вид в onBindView() вашего Adapter, для этого вам нужно связать состояние с каждым элементом в списке адаптеров.

Чтобы разрешить анимацию развернуть/свернуть во время прокрутки просто setDuration(0), которая позволяет вам развернуть/свернуть без каких-либо задержек или анимации для более плавного прокрутки.

+0

Да, я знаю об этом RecyclerView использует ScrappedViews, поэтому я спрашиваю, что я могу с этим сделать. Я попытался сохранить состояние каждого элемента в списке. Я сделал логический массив, чтобы запомнить состояние каждого элемента в recyclerview. Но когда я прокручивал предметы, они рушились во время свитка, и это выглядело странно. Также, когда я нажимаю просмотр каждый раз, когда элементы onBindViewHolder рушится во время прокрутки, и это не идеальное решение. – Zygi

+0

@ Zibiksior Затем добавьте свой «Адаптер» в свой вопрос. – Abbas

+0

Код адаптера отправлен в вопрос – Zygi

0

Ожидается поведение recyclerView. RecyclerView перерабатывает элементы, которые не отображаются. если вы не хотите, чтобы ваши предметы были переработаны, используйте holder.setIsRecyclable (false); в вашем методе onBindViewHolder() вашего адаптера.

holder.setIsRecyclable(false); 
+0

Как насчет производительности при использовании этого решения? – Zygi

+0

он должен работать как listView в этом случае. – saty

+0

Я бы сказал, что это не очень хорошее решение, так как предложение 'setTag' от @Tasos в комментариях решило бы проблему, не влияя на производительность. – Marcel50506

Смежные вопросы