2016-10-03 5 views
0

У меня есть RecyclerView, который отображает серию представлений, полученных из базы данных. Я хочу подтвердить, что пользователь выбрал одно из видов, выделив его края, и мне это удалось. Если пользователь переходит к выбору варианта, я хочу удалить выделение в исходном выборе. Здесь я столкнулся с проблемой.Доступ к ViewHolder, непосредственно из RecyclerView, по положению

Первоначальная подсветка не была проблемой, поскольку я делал это, внутренне. Тем не менее, я не знаю, как получить доступ к предыдущему виду только с позиции адаптера. Я искал StackOverflow около часа, так как я не могу найти много возможностей в Android API или из Google. Многие пользователи, похоже, задают похожие вопросы, но в конечном итоге тонкие различия не дают никаких полезных ответов.

Внутри моей ViewHolder, которая является внутренним public class моего RecyclerView, у меня есть OnClickListener следующим образом:

@Override 
    public void onClick(View view) { 
     if(!selected) { 
      selected = true; 
      view.setBackgroundResource(R.drawable.default_selection_background); 
     } else { 
      selected = false; 
      view.setBackgroundResource(0); 
     } 

     UpdateSelected(getAdapterPosition()); 
    } 

Это указывает обратно на мой RecyclerView, и, честно говоря, я еще добавить любой рабочий код мой UpdateSelected(int position) способ.

Если это поможет, я намерен, чтобы он действовал так:

void UpdateSelected(int position) { 
    if(position != currentlySelected) { 
     ViewHolder[currentlySelected].Deselect(); 
    } 
} 

public class ViewHolder extends RecyclerView.ViewHolder { 
    ... 

    public void Deselect() { 
     // and from here, I can go on as normal. 
    } 
} 

Я заметил пользователей советуя другим использовать getLayoutPosition() вывести позицию для целей пользовательского интерфейса, если они специально не хотите продолжать работать с внутренние данные, которые я намерен делать.

Как мне получить доступ к определенному ViewHolder из моего RecyclerView, используя его положение?

ответ

3

Вы могли бы сделать что-то вроде этого.

В адаптере создайте переменную-член, которая будет отслеживать позицию выбранного элемента.

int selectedPosition = -1; // -1 some default value for nothing selected 

Затем в onBindViewHolder зрения утилизатор адаптер

int backgroundRes = (position == selectedPosition)? R.drawable.default_selection_background : 0; 
    view.setBackgroundResource(backgroundRes); 

Наконец в OnClick вашего viewholder

@Override 
public void onClick(View view) { 
    selectedPosition = getAdapterPosition(); 
    notifyDataSetChanged(); 
} 
+0

Блестящий! работает как шарм. Там только изменения, которые я должен был сделать, были в 'onBindViewHolder', который сразу же имеет доступ к' view'. Я просто использовал 'viewHolder.itemView.setBackgroundResource (backgroundRes)'. Для эффективности я также только «notifyItemChanged» на 'previousSelection' и' currentSelection', но большое вам спасибо. – Gnemlock

+0

Я также сталкиваюсь с той же проблемой. поэтому я пробую это решение, но не работал в моем случае. @Gnemlock –

+0

Я просто наткнулся на этот ответ, и хотя хорошо, я бы предложил изменить 'notifyDataSetChanged()' на 'notifyItemChanged (selectedPosition)'. Рекомендуется избегать вызова 'notifyDataSetChanged()', когда вы можете указать адаптеру точно, какие представления необходимо обновить. –

1

Вы можете получить доступ к viewholder по его позиция из recyclerview

Вот моя реализация

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, 
       recyclerView, new RecyclerItemClickListener.OnItemClickListener() { 
      @Override 
      public void onItemClick(View view, int position) { 
       /*your coding */ 
      } 

      @Override 
      public void onItemLongClick(View view, int position) { 

      } 

     })); 

и создать класс

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { 

    private OnItemClickListener mListener; 
    private GestureDetector mGestureDetector; 
    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) { 
     mListener = listener; 

     mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
      @Override 
      public boolean onSingleTapUp(MotionEvent e) { 
       return true; 
      } 
      @Override 
      public void onLongPress(MotionEvent e) { 
       View childView = recyclerView.findChildViewUnder(e.getX(), e.getY()); 

       if (childView != null && mListener != null) { 
        mListener.onItemLongClick(childView, recyclerView.getChildPosition(childView)); 
       } 
      } 
     }); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { 
     View childView = view.findChildViewUnder(e.getX(), e.getY()); 
     if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { 
      mListener.onItemClick(childView, view.getChildPosition(childView)); 
     } 
     return false; 
    } 

    @Override 
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { 
    } 

    @Override 
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 

    } 
    public interface OnItemClickListener { 
     void onItemClick(View view, int position); 
     void onItemLongClick(View view, int position); 
    } 
} 
0

Вместо замены фона ресурс вручную, вместо того, чтобы можно пометить точку зрения, как выбран или нет, и есть Android изменить фон с помощью выталкиваемых селекторов.

res/drawable/background.XML:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_selected="true" android:drawable="@drawable/default_selection_background" /> 
    <item android:drawable="@null" /> 
</selector> 

background.xml будет установлен в качестве android:background в макет XML вашего элемента.

Тогда в вашем onBindViewHolder(ViewHolder holder, int position) обновить состояние Android Вид:

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 
    boolean isSelected = position == selectedPosition; 
    holder.itemView.setSelected(isSelected); 
} 

Для меня, я бы предпочел, имеющий адаптер, который был глупее и имел меньше логики. Вы можете сделать это, сохранив список ViewModels (классы данных, которые отображают то, что вы покажете в представлении - не более, не менее), где одним из свойств может быть выбранный флаг (в каждой ViewModel).

Когда пользователь выбирает или отменяет выбор вида, обратный вызов выдает обновление ведущему, которое затем обновляет адаптер и уведомляет адаптер, какие позиции были обновлены. Это означало бы сохранение текущего выбранного элемента (желательно ID, но может хранить ViewModel или позицию) в презентаторе, чтобы вы могли его обновить.

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