Получить щелкнутый элемент и его положение в RecyclerView



я заменяю мой ListView с RecyclerView, список показывает ок, но я хотел бы знать, как получить элемент и его позицию, похож на метод OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id) мы используем в ListView.



Спасибо за идеи!

1252   17  

17 ответов:

на основе ссылки:почему RecyclerView не имеет onItemClickListener ()? и чем RecyclerView отличается от Listview?, а также общая идея @Duncan, я даю свое решение здесь:

  • определить один интерфейс RecyclerViewClickListener для передачи сообщения от адаптера к Activity/Fragment:

    public interface RecyclerViewClickListener {
        public void recyclerViewListClicked(View v, int position);
    }
    
  • на Activity/Fragment реализует интерфейс, а также передать слушателю адаптер:

    @Override
    public void recyclerViewListClicked(View v, int position){... ...}
    
    //set up adapter and pass clicked listener this
    myAdapter = new MyRecyclerViewAdapter(context, this);
    
  • на Adapter и ViewHolder:

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {
       ... ... 
       private Context context;
       private static RecyclerViewClickListener itemListener;
    
    
       public MyRecyclerViewAdapter(Context context, RecyclerViewClickListener itemListener) {
           this.context = context;
           this.itemListener = itemListener;
           ... ...
       }
    
    
       //ViewHolder class implement OnClickListener, 
       //set clicklistener to itemView and, 
       //send message back to Activity/Fragment 
       public static class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
           ... ...
           public ItemViewHolder(View convertView) {
               super(convertView);
               ... ...
               convertView.setOnClickListener(this);
           }
    
           @Override
           public void onClick(View v) {
               itemListener.recyclerViewListClicked(v, this.getPosition());     
    
           }
       }
    }
    

после тестирования, он работает нормально.


[обновление]

начиная с API 22,RecyclerView.ViewHoler.getPosition() устарел, так что вместо этого с getLayoutPosition().

public class MyRvAdapter extends RecyclerView.Adapter<MyRvAdapter.MyViewHolder>{
    public Context context;
    public ArrayList<RvDataItem> dataItems;

    ...
    constructor
    overrides
    ...

    class MyViewHolder extends RecyclerView.ViewHolder{
        public TextView textView;
        public Context context;

        public MyViewHolder(View itemView, Context context) {
            super(itemView);

            this.context = context;

            this.textView = (TextView)itemView.findViewById(R.id.textView);

            // on item click
            itemView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    // get position
                    int pos = getAdapterPosition();

                    // check if item still exists
                    if(pos != RecyclerView.NO_POSITION){
                        RvDataItem clickedDataItem = dataItems.get(pos);
                        Toast.makeText(v.getContext(), "You clicked " + clickedDataItem.getName(), Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
}

вот пример установки прослушивателя щелчков.

Adapter extends  RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {  ...  }

 public static class MessageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView     tv_msg;
        public TextView     tv_date;
        public TextView     tv_sendTime;
        public ImageView    sharedFile;
        public ProgressBar sendingProgressBar;

        public MessageViewHolder(View v) {
            super(v);
            tv_msg =  (TextView) v.findViewById(R.id.tv_msg);
            tv_date = (TextView)  v.findViewById(R.id.tv_date);
            tv_sendTime = (TextView)  v.findViewById(R.id.tv_sendTime);
            sendingProgressBar = (ProgressBar) v.findViewById(R.id.sendingProgressBar);
            sharedFile = (ImageView) v.findViewById(R.id.sharedFile);

            sharedFile.setOnClickListener(this);

        }

        @Override
        public void onClick(View view) {
        int position  =   getAdapterPosition();


            switch (view.getId()){
                case R.id.sharedFile:


                    Log.w("", "Selected"+position);


                    break;
            }
        }

    }

поместите этот код, где вы определяете представление recycler в activity.

    rv_list.addOnItemTouchListener(
            new RecyclerItemClickListener(activity, new RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {

                    Toast.makeText(activity, "" + position, Toast.LENGTH_SHORT).show();
                }
            })
    );

затем сделайте отдельный класс и поместите этот код:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

    private OnItemClickListener mListener;
    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }
    GestureDetector mGestureDetector;
    public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
        mListener = listener;
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }
        });
    }
    @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.getChildAdapterPosition(childView));
        }
        return false;
    }

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

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

Если вы хотите щелкнуть событие recycle-View из activity / fragment вместо adapter, вы также можете использовать следующий короткий путь.

recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                final TextView txtStatusChange = (TextView)v.findViewById(R.id.txt_key_status);
                txtStatusChange.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e(TAG, "hello text " + txtStatusChange.getText().toString() + " TAG " + txtStatusChange.getTag().toString());
                        Util.showToast(CampaignLiveActivity.this,"hello");
                    }
                });
                return false;
            }
        });

вы также можете использовать другие длинные способы, такие как использование интерфейса

recyclerViewObject.addOnItemTouchListener(
    new RecyclerItemClickListener(
        getContext(),
        recyclerViewObject,
        new RecyclerItemClickListener.OnItemClickListener() {
            @Override public void onItemClick(View view, int position) {
                // view is the clicked view (the one you wanted
                // position is its position in the adapter
            }
            @Override public void onLongItemClick(View view, int position) {
            }
        }
    )
);

использовать ниже код:-

public class SergejAdapter extends RecyclerView.Adapter<SergejAdapter.MyViewHolder>{

...

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // here you use position
        int position = getAdapterPosition();
        ...

    }
}
}

RecyclerView не предоставляет такой метод.

для управления событиями щелчка на RecyclerView я закончил реализацию onClickListener в моем адаптере, при привязке ViewHolder: в моем ViewHolder я сохраняю ссылку на корневое представление (как вы можете сделать с вашими ImageViews, TextViews и т. д...) и при привязке viewHolder я устанавливаю тег на нем с информацией, которую мне нужно обработать click (например, position) и clicklistener

//Create below methods into the Activity which contains RecyclerView.


private void createRecyclerView() {

final RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    MyAdapter myAdapter=new MyAdapter(dataAray,MianActivity.this);
    recyclerView.setAdapter(myAdapter);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    setRecyclerViewClickListner(recyclerView);
}

private void setRecyclerViewClickListner(RecyclerView recyclerView){

    final GestureDetector gestureDetector = new GestureDetector(MainActivity.this,new GestureDetector.SimpleOnGestureListener() {
        @Override public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });


    recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
            View child =recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
            if(child!=null && gestureDetector.onTouchEvent(motionEvent)){
               int position=recyclerView.getChildLayoutPosition(child);
                String name=itemArray.get(position).name;

            return true;
        }

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

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean b) {

        }
    });
}

попробуйте таким образом

класс адаптера :

 public class ContentAdapter extends RecyclerView.Adapter<ContentAdapter.ViewHolder> {

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

private final List<ContentItem> items;
private final OnItemClickListener listener;

public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
    this.items = items;
    this.listener = listener;
}

@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false);
    return new ViewHolder(v);
}

@Override public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(items.get(position), listener);
}

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

static class ViewHolder extends RecyclerView.ViewHolder {

    private TextView name;
    private ImageView image;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.name);
        image = (ImageView) itemView.findViewById(R.id.image);
    }

    public void bind(final ContentItem item, final OnItemClickListener listener) {
        name.setText(item.name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                listener.onItemClick(item);
            }
        });
    }
}

}

в вашей деятельности или фрагмент :

ContentAdapter adapter = new ContentAdapter(itemList, this);

Примечание : реализовать OnItemClickListener на основе контекста, который вы указали в деятельности или фрагмент и переопределению методов.

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

вместо этого я использую этот подход и просто сохраняю его в ViewHolder при вызове onBindViewHolder() и устанавливаю ссылку на null в onViewRecycled().

каждый раз, когда ViewHolder становится невидимым, он не знает. Так что это не влияет на большое потребление памяти.

@Override
public void onBindViewHolder(final ItemViewHolder holder, int position) {
    ...
    holder.displayedItem = adapterItemsList.get(i);
    ...
}

@Override
public void onViewRecycled(ItemViewHolder holder) {
    ...
    holder.displayedItem = null;
    ...
}

class ItemViewHolder extends RecyclerView.ViewHolder {
    ...
    MySuperItemObject displayedItem = null;
    ...
}

короткое расширение для Котлин
Метод возвращает абсолютное положение всех элементов (не только положение видимых элементов).

fun RecyclerView.getChildPositionAt(x: Float, y: Float): Int {
    return getChildAdapterPosition(findChildViewUnder(x, y))
}

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

val position = recyclerView.getChildPositionAt(event.x, event.y)

вот самый простой и легкий способ найти положение нажатого элемента:

Я также столкнулся с той же проблемой.

Я хотел найти позицию нажатого / выбранного элемента RecyclerView () и выполнить некоторые конкретные операции над этим конкретным элементом.

getAdapterPosition () метод работает как шарм для такого рода вещей. Я нашел этот способ после долгих исследований и после попытки многих других методы.

int position = getAdapterPosition();
Toast.makeText(this, "Position is: "+position, Toast.LENGTH_SHORT).show();

вы не должны использовать какой-либо дополнительный метод. Просто создайте глобальную переменную с именем 'position' и инициализируйте ее с помощью getAdapterPosition() в любом из основных методов адаптера (класса или аналогичного).

вот краткая документация из этого ссылке.

getAdapterPosition добавлено в версии 22.1.0 int getAdapterPosition () Возвращает положение адаптера элемента, представленного этим держателем вида. Заметить что это может отличаться от getLayoutPosition (), если есть ожидающие обновления адаптера, но новый проход макета еще не произошел. RecyclerView не обрабатывает обновления адаптера до следующего обхода макета. Это может привести к временному несоответствию между тем, что пользователь видит на экране, и содержимым адаптера. Это несоответствие не важно, так как оно будет меньше 16 мс, но это может быть проблемой, если вы хотите использовать позицию ViewHolder для доступа к адаптеру. Иногда, возможно, вам потребуется получить точное положение адаптера, чтобы выполнить некоторые действия в ответ на события пользователя. В этом случае, вы должны использовать этот метод, который будет вычислять положение адаптера ViewHolder.

рады вам помочь. Не стесняйтесь задавать вопросы.

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

https://becody.com/get-clicked-item-and-its-position-in-recyclerview/

из конструктора, вы можете установить onClick свойство listItem к методу, определенному с помощью одного параметра. У меня есть пример метода, определенного ниже. В getAdapterPosition способ даст вам индекс выбранного listitem элемент.

public void exampleOnClickMethod(View view){
    myRecyclerView.getChildViewHolder(view).getAdapterPosition());
}

для получения информации о настройке RecyclerView см. документацию здесь:https://developer.android.com/guide/topics/ui/layout/recyclerview

просто добавьте прослушиватель касания элемента на свой объект RecyclerView.

recyclerView.addOnItemTouchListener(  
new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
  @Override public void onItemClick(View view, int position) {
    // TODO Handle item click
  }
}));

в onViewHolder установите onClickListiner в любое представление и в боковом щелчке используйте этот код:

тосты.makeText (Drawer_bar.это, "позиция" + позиция, тост.LENGTH_SHORT).показать();

заменить Drawer_Bar с вашим именем деятельности.

Comments

    Ничего не найдено.