34

Я экспериментирую с recyclerview и карточками поддержки библиотеки. У меня есть переработка карт. Каждая карта имеет значок «х» в правом верхнем углу, чтобы удалить его:Как получить позицию, выбранную в RecyclerView?

XML-карта, list_item.xml:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v7.widget.CardView 
xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:layout_margin="5dp"> 
<RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
    <TextView 
     android:id="@+id/taskDesc" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:textSize="40sp" 
     android:text="hi"/> 
    <ImageView 
     android:id="@+id/xImg" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentTop="true" 
     android:layout_alignParentRight="true" 
     android:src="@drawable/ic_remove"/> 
</RelativeLayout> 
</android.support.v7.widget.CardView> 

Я попытался пометить строку с позиции я хотел бы использовать в notifyItemRemoved(position) в TaskAdapter.java :

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder> { 

private List<Task> taskList; 
private TaskAdapter thisAdapter = this; 


// cache of views to reduce number of findViewById calls 
public static class TaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 
    protected TextView taskTV; 
    protected ImageView closeBtn; 
    public TaskViewHolder(View v) { 
     super(v); 
     taskTV = (TextView)v.findViewById(R.id.taskDesc); 
    } 

    @Override 
    public void onClick(View v) { 
     int position = v.getTag(); 
     adapter.notifyItemRemoved(position); 
    } 
} 


public TaskAdapter(List<Task> tasks) { 
    if(tasks == null) 
     throw new IllegalArgumentException("tasks cannot be null"); 
    taskList = tasks; 
} 


// onBindViewHolder binds a model to a viewholder 
@Override 
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) { 
    final int position = pos; 
    Task currTask = taskList.get(pos); 
    taskViewHolder.taskTV.setText(currTask.getDescription()); 

    taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      thisAdapter.notifyItemRemoved(position); 
     } 
    }); 
} 

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


// inflates row to create a viewHolder 
@Override 
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos) { 
    View itemView = LayoutInflater.from(parent.getContext()). 
            inflate(R.layout.list_item, parent, false); 

    return new TaskViewHolder(itemView); 
} 
} 

Это не будет работать, потому что вы не можете установить тег не может получить доступ к адаптер от onClick.

ответ

73

Установите слушателей onClick на onBindViewHolder, и вы можете получить доступ к позиции оттуда. Если вы установите их в ViewHolder вы не будете знать, что позиция была нажата, если вы не пройдете позицию в ViewHolder

EDIT

Как pskink отметил ViewHolder имеет getPosition так, как вы были первоначально делать это было правильно.

Когда представление щелкнул вы можете использовать getPosition в вашем ViewHolder и возвращает позицию

Update

getPosition() теперь устарела и заменяется getAdapterPosition()

+2

Можете ли вы показать код? Как это сделать, если у taskViewHolder нет метода setOnClickListener? –

+0

Вы используете вид от зрителя там – tyczj

+1

@tyczj no, лучшее место - установить слушателя в ViewHolder ctor, ViewHolders знают свои собственные позиции – pskink

6

В дополнение @tyczj ответ:

Общий код Pseido:

public abstract class GenericRecycleAdapter<T, K extends RecyclerView.ViewHolder> extends RecyclerView.Adapter{ 

private List<T> mList; 
//default implementation code 

public abstract int getLayout(); 

@Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View v = LayoutInflater.from(parent.getContext()) 
       .inflate(getLayout(), parent, false); 
     return getCustomHolder(v); 
    } 

    public Holders.TextImageHolder getCustomHolder(View v) { 
     return new Holders.TextImageHolder(v){ 
      @Override 
      public void onClick(View v) { 
       onItem(mList.get(this.getAdapterPosition())); 
      } 
     }; 
    } 

abstract void onItem(T t); 

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
    onSet(mList.get(position), (K) holder); 

} 

public abstract void onSet(T item, K holder); 

} 

ViewHolder: использование

public class Holders { 

    public static class TextImageHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ 

     public TextView text; 

     public TextImageHolder(View itemView) { 
      super(itemView); 
      text = (TextView) itemView.findViewById(R.id.text); 
      text.setOnClickListener(this); 


     } 

     @Override 
     public void onClick(View v) { 

     } 
    } 


} 

адаптер:

public class CategoriesAdapter extends GenericRecycleAdapter<Category, Holders.TextImageHolder> { 


    public CategoriesAdapter(List<Category> list, Context context) { 
     super(list, context); 
    } 

    @Override 
    void onItem(Category category) { 

    } 


    @Override 
    public int getLayout() { 
     return R.layout.categories_row; 
    } 

    @Override 
    public void onSet(Category item, Holders.TextImageHolder holder) { 

    } 



} 
12

Другой способ - с помощью SetTag() и GetTag() методы класса View.

  1. использование SetTag() в методе onBindViewHolder вашего адаптера

    @Override 
    public void onBindViewHolder(myViewHolder viewHolder, int position) { 
        viewHolder.mCardView.setTag(position); 
    } 
    

    где mCardView определен в классе myViewHolder

    private class myViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 
          public View mCardView; 
    
          public myViewHolder(View view) { 
           super(view); 
           mCardView = (CardView) view.findViewById(R.id.card_view); 
    
           mCardView.setOnClickListener(this); 
          } 
         } 
    
  2. использование GetTag() в ваша реализация OnClickListener

    @Override 
    public void onClick(View view) { 
        int position = (int) view.getTag();   
    
    //display toast with position of cardview in recyclerview list upon click 
    Toast.makeText(view.getContext(),Integer.toString(position),Toast.LENGTH_SHORT).show(); 
    } 
    

см https://stackoverflow.com/a/33027953/4658957 для более подробной информации

5
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 

    FrameLayout root; 


    public ViewHolder(View itemView) { 
     super(itemView); 

     root = (FrameLayout) itemView.findViewById(R.id.root); 
     root.setOnClickListener(this); 
    } 


    @Override 
    public void onClick(View v) { 
     LogUtils.errorLog("POS_CLICKED: ",""+getAdapterPosition()); 
    } 
} 
1

Я решил этот путь

class MyOnClickListener implements View.OnClickListener { 
     @Override 
     public void onClick(View v) { 

      int itemPosition = mRecyclerView.getChildAdapterPosition(v); 

      myResult = results.get(itemPosition); 


     } 
    } 

И в адаптере

@Override 
     public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 
                 int viewType) {    
      View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_wifi, parent, false); 
      v.setOnClickListener(new MyOnClickListener()); 
      ViewHolder vh = new ViewHolder(v); 
      return vh; 
     } 
+0

, пожалуйста, уточните свой ответ, что вы сделали в коде. – swiftBoy

2

Получить целенаправленный ребенка, и использовать его получить pos ition в адаптере.

mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild()) 
1

Я думаю, что самый правильный способ получить позицию элемента является

View.OnClickListener onClickListener = new View.OnClickListener() { 
    @Override public void onClick(View v) { 
     View view = v; 
     View parent = (View) v.getParent(); 
     while (!(parent instanceof RecyclerView)){ 
     view=parent; 
     parent = (View) parent.getParent(); 
     } 
     int position = recyclerView.getChildAdapterPosition(view); 
} 

Поскольку точки зрения, вы щелкаете не всегда вид корневой макете строки. Если представление не является корневым (например, кнопки), вы получите исключение класса. Таким образом, сначала нам нужно найти представление, которое является регрессивным ребёнком из вас reciclerview. Затем найдите позицию, используя recyclerView.getChildAdapterPosition (view);

3

Лично самый простой способ, который я нашел и работает для меня заключается в следующем:

Создайте интерфейс внутри вашего «RecycleAdapter» класса (Подкласс)

public interface ClickCallback { 
    void onItemClick(int position); 
} 

Добавить переменная интерфейса в качестве параметра в конструкторе.

private String[] items; 
private ClickCallback callback; 

public RecyclerAdapter(String[] items, ClickCallback clickCallback) { 
    this.items = items; 
    this.callback = clickCallback; 
} 

Установите Click слушателя в ViewHolder (другой подкласс) и передать «положение» на через интерфейс

AwesomeViewHolder(View itemView) { 
     super(itemView); 
     itemView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       callback.onItemClick(getAdapterPosition()); 
      } 
     }); 
     mTextView = (TextView) itemView.findViewById(R.id.mTextView); 
    } 

Теперь при инициализации адаптера ресайклер в деятельности/фрагмент, просто создайте новый «ClickCallback» (интерфейс)

String[] values = {"Hello","World"}; 
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(values, new RecyclerAdapter.ClickCallback() { 
    @Override 
    public void onItemClick(int position) { 
     // Do anything with the item position 
    } 
}); 

Вот и все для меня. :)