web-dev-qa-db-fra.com

Comment puis-je obtenir la position sélectionnée dans un RecyclerView?

J'expérimente avec les cartes de recyclage de la bibliothèque d'assistance. J'ai un recyclage des cartes. Chaque carte a une icône «x» dans le coin supérieur droit pour la supprimer:

La carte 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>

J'ai tenté de baliser la ligne avec la position que j'utiliserais dans notifyItemRemoved(position) dans 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);
}
}

Cela ne fonctionnera pas car vous ne pouvez pas définir de tag ni accéder à l'adaptateur à partir de onClick.

47
HukeLau_DABA

Définissez votre onClickListeners sur onBindViewHolder() et vous pourrez accéder à la position à partir de là. Si vous les définissez dans votre ViewHolder, vous ne saurez pas quelle position a été cliquée, sauf si vous passez également la position dans la ViewHolder

MODIFIER

Comme pskink l'a fait remarquer, ViewHolder a un getPosition() et la façon dont vous le faisiez à l'origine était correcte.

Lorsque la vue est cliquée, vous pouvez utiliser getPosition() dans votre ViewHolder et il renvoie la position

Mettre à jour

getPosition() est maintenant obsolète et remplacé par getAdapterPosition()

91
tyczj

Une méthode différente - en utilisant les méthodes setTag () et getTag () de la classe View.

  1. utilisez setTag () dans la méthode onBindViewHolder de votre adaptateur

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

    où mCardView est défini dans la classe 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. utilisez getTag () dans votre implémentation 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();
    }
    

voir https://stackoverflow.com/a/33027953/4658957 pour plus de détails

15
bastien

Pour compléter la réponse de @tyczj:

Code générique de l'adaptateur 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) {

        }
    }


}

Utilisation de l'adaptateur:

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

Personnellement, la manière la plus simple que j'ai trouvée et fonctionne bien pour moi est la suivante:

Créez une interface dans votre classe "RecycleAdapter" (sous-classe)

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

Ajouter une variable de l'interface en tant que paramètre dans le constructeur.

private String[] items;
private ClickCallback callback;

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

Définissez un écouteur de clic dans ViewHolder (une autre sous-classe) et transmettez la position à travers l'interface

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

Maintenant, lors de l'initialisation de l'adaptateur de recycleur dans une activité/un fragment, créez simplement un nouveau 'ClickCallback' (interface)

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

C'est tout pour moi. :)

3
Yusuph wickama

J'ai résolu de cette façon

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

            int itemPosition = mRecyclerView.getChildAdapterPosition(v);

            myResult = results.get(itemPosition);


        }
    }

Et dans l'adaptateur

@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

Obtenez un enfant concentré et utilisez-le pour obtenir une position dans l'adaptateur.

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

1. Créer la classe Nom 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. Appelez 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) {

    }
}));

Je pense que le moyen le plus correct d’obtenir la position de l’article est

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

Parce que vue, vous ne cliquez pas toujours sur la vue racine de votre disposition de lignes. Si view n’est pas une racine (par exemple des boutons), vous obtiendrez une exception de conversion en classe. Ainsi, au début, nous devons trouver la vue, qui est l’enfant direct de votre aperçu. Ensuite, recherchez la position en utilisant recyclerView.getChildAdapterPosition (view);

1
Yarh

onBindViewHolder () est appelé pour chaque élément. Définir l'écouteur de clics dans onBindVieHolder () est une option inutile à répéter lorsque vous pouvez l'appeler une fois dans votre constructeur 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

Pas besoin que votre ViewHolder implémente View.OnClickListener. Vous pouvez obtenir directement la position cliquée en définissant un écouteur de clic dans la méthode onCreateViewHolder de RecyclerView.Adapter. Voici un exemple de code:

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
Mouss