【问题标题】:How do I get the position selected in a RecyclerView?如何在 RecyclerView 中选择位置?
【发布时间】:2014-12-28 05:20:21
【问题描述】:

我正在试验支持库的 recyclerview 和卡片。我有卡片的recyclerview。每张卡片的右上角都有一个“x”图标,可将其移除:

卡片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.访问适配器

【问题讨论】:

    标签: android android-support-library android-recyclerview android-cardview


    【解决方案1】:

    将您的onClickListeners 设置为onBindViewHolder(),您就可以从那里访问该职位。如果您将它们设置在您的ViewHolder 中,您将不知道点击了哪个位置,除非您还将该位置传递给ViewHolder

    编辑

    正如pskink 指出的ViewHolder 有一个getPosition(),所以你最初的做法是正确的。

    点击视图时,您可以在ViewHolder 中使用getPosition() 并返回位置

    更新

    getPosition() 现已弃用并替换为 getAdapterPosition()

    2020 年更新

    getAdapterPosition() 现在已弃用并替换为 getAbsoluteAdapterPosition()getBindingAdapterPosition()

    Kotlin 代码:

    override fun onBindViewHolder(holder: MyHolder, position: Int) {
            // - get element from your dataset at this position
            val item = myDataset.get(holder.absoluteAdapterPosition)
        }
    

    【讨论】:

    • 你能显示一些代码吗?如果 taskViewHolder 没有 setOnClickListener 方法,我该怎么做?
    • 您使用那里的viewholder中的视图
    • @tyczj 不,更好的地方是在 ViewHolder ctor 中设置 listener,ViewHolder 知道自己的位置
    • @pskink 如果不将位置传递给构造函数,您将如何知道位置呢?
    • @tyczj ViewHolder.getPosition(),顺便说一句,当你创建一个 ViewHolder 时你不知道位置,位置是在 onBindViewHolder 中设置的
    【解决方案2】:

    另一种方法 - 使用 View 类的 setTag()getTag() 方法。

    1. 在适配器的 onBindViewHolder 方法中使用 setTag()

      @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. 在您的 OnClickListener 实现中使用 getTag()

      @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了解更多详情

    【讨论】:

    • 太棒了!简单而最好的
    【解决方案3】:

    补充@tyczj 答案:

    通用适配器伪代码:

    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) {
    
        }
    
    
    
    }
    

    【讨论】:

      【解决方案4】:
       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());
          }
      }
      

      【讨论】:

        【解决方案5】:

        就我个人而言,我发现并且最适合我的最简单方法如下:

        在“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;
        }
        

        在 ViewHolder(另一个子类)中设置 Click 监听器,并通过接口传递“位置”

            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
            }
        });
        

        对我来说就是这样。 :)

        【讨论】:

          【解决方案6】:

          我是这样解决的

          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;
                  }
          

          【讨论】:

          • 请详细说明你的答案,你在代码中做了什么。
          【解决方案7】:

          获得专注的孩子,并使用它来获得适配器中的位置。

          mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())
          

          【讨论】:

            【解决方案8】:

            1.创建类名 RecyclerTouchListener.java

            import android.content.Context;
            import android.support.v7.widget.RecyclerView;
            import android.view.GestureDetector;
            import android.view.MotionEvent;
            import android.view.View;
            
            public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener 
            {
            
            private GestureDetector gestureDetector;
            private ClickListener clickListener;
            
            public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
                this.clickListener = clickListener;
                gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {
                        return true;
                    }
            
                    @Override
                    public void onLongPress(MotionEvent e) {
                        View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                        if (child != null && clickListener != null) {
                            clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
                        }
                    }
                });
            }
            
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            
                View child = rv.findChildViewUnder(e.getX(), e.getY());
                if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
                    clickListener.onClick(child, rv.getChildAdapterPosition(child));
                }
                return false;
            }
            
            @Override
            public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            }
            
            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
            
            }
            
            public interface ClickListener {
                void onClick(View view, int position);
            
                void onLongClick(View view, int position);
            }
            }
            

            2。调用 RecyclerTouchListener

            recycleView.addOnItemTouchListener(new RecyclerTouchListener(this, recycleView, 
            new RecyclerTouchListener.ClickListener() {
                @Override
                public void onClick(View view, int position) {
                    Toast.makeText(MainActivity.this,Integer.toString(position),Toast.LENGTH_SHORT).show();
                }
            
                @Override
                public void onLongClick(View view, int position) {
            
                }
            }));
            

            【讨论】:

              【解决方案9】:

              我认为获取项目位置最正确的方法是

              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);
              }
              

              因为视图,您单击的并不总是行布局的根视图。如果视图不是根视图(例如按钮),您将获得 Class cast 异常。因此,首先我们需要找到视图,它是您的 reciclerview 的直接孩子。然后,使用 recyclerView.getChildAdapterPosition(view); 找到位置;

              【讨论】:

                【解决方案10】:

                onBindViewHolder() 会为每个项目调用,并且在 onBindVieHolder() 中设置点击侦听器是不必要的重复选项,您可以在 ViewHolder 构造函数中调用一次。

                public class MyViewHolder extends RecyclerView.ViewHolder 
                      implements View.OnClickListener{
                   public final TextView textView; 
                
                   public MyViewHolder(View view){
                      textView = (TextView) view.findViewById(R.id.text_view);
                      view.setOnClickListener(this);
                      // getAdapterPosition() retrieves the position here.
                   } 
                
                   @Override
                   public void onClick(View v){
                      // Clicked on item 
                      Toast.makeText(mContext, "Clicked on position: " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
                   }
                }
                

                【讨论】:

                  【解决方案11】:

                  无需让您的 ViewHolder 实现 View.OnClickListener。您可以通过在 RecyclerView.Adapter 的 onCreateViewHolder 方法中设置点击监听器直接获取点击位置,这里是代码示例:

                  public class ItemListAdapterRecycler extends RecyclerView.Adapter<ItemViewHolder>
                  {
                  
                      private final List<Item> items;
                  
                      public ItemListAdapterRecycler(List<Item> items)
                      {
                          this.items = items;
                      }
                  
                      @Override
                      public ItemViewHolder onCreateViewHolder(final ViewGroup parent, int viewType)
                      {
                          View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
                  
                          view.setOnClickListener(new View.OnClickListener()
                          {
                              @Override
                              public void onClick(View view)
                              {
                                  int currentPosition = getClickedPosition(view);
                                  Log.d("DEBUG", "" + currentPosition);
                              }
                          });
                  
                          return new ItemViewHolder(view);
                      }
                  
                      @Override
                      public void onBindViewHolder(ItemViewHolder itemViewHolder, int position)
                      {
                          ...
                      }
                  
                      @Override
                      public int getItemCount()
                      {
                          return items.size();
                      }
                  
                      private int getClickedPosition(View clickedView)
                      {
                          RecyclerView recyclerView = (RecyclerView) clickedView.getParent();
                          ItemViewHolder currentViewHolder = (ItemViewHolder) recyclerView.getChildViewHolder(clickedView);
                          return currentViewHolder.getAdapterPosition();
                      }
                  
                  }
                  

                  【讨论】:

                    【解决方案12】:
                    @Override
                    public void onClick(View v) {
                         int pos = getAdapterPosition();
                    }
                    

                    就这么简单,ViewHolder

                    【讨论】:

                      【解决方案13】:

                      使用数据绑定时,您需要从项目的点击侦听器内部知道 RecyclerView 点击位置:

                      科特林

                          val recyclerView = view.parent as RecyclerView
                          val position = recyclerView.getChildAdapterPosition(view)
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2019-04-05
                        • 1970-01-01
                        • 2016-08-27
                        • 2019-01-11
                        相关资源
                        最近更新 更多