web-dev-qa-db-ja.com

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>

TaskAdapter.JavanotifyItemRemoved(position)で使用する位置で行にタグを付けようとしました:

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.からアダプターにアクセスできないため、これは機能しません。

52
HukeLau_DABA

onClickListenersをonBindViewHolder()に設定すると、そこからポジションにアクセスできます。それらをViewHolderに設定すると、その位置もViewHolderに渡さない限り、どの位置がクリックされたかわかりません。

編集

pskinkが指摘したようにViewHolderにはgetPosition()がありますので、元々のやり方は正しかったです。

ビューをクリックすると、ViewHoldergetPosition()を使用でき、位置を返します

更新

getPosition()は廃止され、getAdapterPosition()に置き換えられました

Kotlinコード:

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

別の方法-setTag()およびgetTag()メソッドの使用Viewクラス。

  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 を参照してください

14
bastien

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

    }



}
8
Mikelis Kaneps
 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
notdrone

個人的に、私が見つけて、私にとって素晴らしい仕事をする最も簡単な方法は以下の通りです:

「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(別のサブクラス)にクリックリスナーを設定し、インターフェイスを介して「位置」を渡します

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

これで終わりです。 :)

3
Yusuph wickama

このように解決しました

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

フォーカスされた子を取得し、それを使用してアダプターの位置を取得します。

mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())
2
Quacker

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

    }
}));

アイテムの位置を取得する最も正しい方法は

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);を使用して位置を見つけます。

1
Yarh
@Override
public void onClick(View v) {
     int pos = getAdapterPosition();
}

ViewHolderのように簡単

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();
   }
}
0
oiyio

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

}
0
Moussa