1048 Stimmen

Warum hat RecyclerView keine onItemClickListener()?

Ich habe RecyclerView erkundet und war überrascht zu sehen, dass RecyclerView keine onItemClickListener() hat.

Ich habe zwei Fragen.

Hauptfrage

Ich möchte wissen, warum Google onItemClickListener() entfernt hat?

Gibt es ein Leistungsproblem oder etwas anderes?

Nebenfrage

Ich habe mein Problem gelöst, indem ich onClick in meinem RecyclerView.Adapter geschrieben habe:

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

    public TextView txtViewTitle;
    public ImageView imgViewIcon;

    public ViewHolder(View itemLayoutView) {
        super(itemLayoutView);
        txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
        imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
    }

    @Override
    public void onClick(View v) {

    }
}

Ist das okay / gibt es einen besseren Weg?

21voto

waqas ali Punkte 1228

Leute verwenden diesen Code in Ihrer Hauptaktivität. Sehr effiziente Methode

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);            
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);

Hier ist Ihre Adapterklasse.

public class UsersAdapter extends RecyclerView.Adapter {
        private ArrayList mDataSet;
        OnCardClickListner onCardClickListner;

        public UsersAdapter(ArrayList mDataSet) {
            this.mDataSet = mDataSet;
        }

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

        @Override
        public void onBindViewHolder(UserViewHolder holder, final int position) {
            holder.name_entry.setText(mDataSet.get(position).getUser_name());
            holder.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onCardClickListner.OnCardClicked(v, position);
                }
            });
        }

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

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
        }

        public static class UserViewHolder extends RecyclerView.ViewHolder {
            CardView cardView;
            TextView name_entry;

            public UserViewHolder(View itemView) {
                super(itemView);
                cardView = (CardView) itemView.findViewById(R.id.user_layout);
                name_entry = (TextView) itemView.findViewById(R.id.name_entry);
             }
        }

        public interface OnCardClickListner {
            void OnCardClicked(View view, int position);
        }

        public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
            this.onCardClickListner = onCardClickListner;
        }
    }

Nach diesem erhalten Sie diese Überschreibmethode in Ihrer Aktivität.

@Override
    public void OnCardClicked(View view, int position) {
        Log.d("OnClick", "Kartenposition" + position);
    }

16voto

EpicPandaForce Punkte 75417

RecyclerView hat kein onItemClickListener, denn RecyclerView ist für das Recycling von Ansichten (Überraschung!) verantwortlich, daher liegt es in der Verantwortung der Ansicht, die recycelt wird, die empfangenen Klick-Ereignisse zu behandeln.

Dies macht die Verwendung tatsächlich viel einfacher, insbesondere wenn Sie Elemente haben, die an mehreren Stellen geklickt werden können.


Wie auch immer, das Erkennen eines Klicks auf ein RecyclerView-Element ist sehr einfach. Alles, was Sie tun müssen, ist ein Interface zu definieren (wenn Sie kein Kotlin verwenden, in diesem Fall übergeben Sie einfach ein Lambda):

public class MyAdapter extends RecyclerView.Adapter {
    private final Clicks clicks;

    public MyAdapter(Clicks clicks) {
        this.clicks = clicks;
    }

    private List items = Collections.emptyList();

    public void updateData(List items) {
        this.items = items;
        notifyDataSetChanged(); // TODO: verwenden Sie bei Bedarf ListAdapter für das Differenzieren, wenn Sie Animationen benötigen
    }

    public interface Clicks {
        void onItemSelected(MyObject myObject, int position);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private MyObject myObject;    

        public MyViewHolder(View view) {
            super(view);
            // Ansichten binden
            view.setOnClickListener((v) -> {
                int adapterPosition = getBindingAdapterPosition();
                if(adapterPosition >= 0) {
                    clicks.onItemSelected(myObject, adapterPosition);
                }
            });
        }

        public void bind(MyObject myObject) {
            this.myObject = myObject;
            // Daten an Ansichten binden
        }
    }
}

Derselbe Code in Kotlin:

class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter() {
    private var items: List = Collections.emptyList()

    fun updateData(items: List) {
        this.items = items
        notifyDataSetChanged() // TODO: verwenden Sie bei Bedarf ListAdapter für das Differenzieren, wenn Sie Animationen benötigen
    }

    inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
        private lateinit var myObject: MyObject

        init {
            // Ansichten binden
            myView.onClick {
                val adapterPosition = getBindingAdapterPosition()
                if(adapterPosition >= 0) {
                    itemClicks.invoke(myObject, adapterPosition)
                }
            }
        }

        fun bind(myObject: MyObject) {
            this.myObject = myObject
            // Daten an Ansichten binden
        }
    }
}

Die Dinge, die Sie NICHT tun müssen:

1.) Sie müssen Touch-Ereignisse nicht manuell abfangen

2.) Sie müssen nicht mit Kind-Attach-Zustandsänderungs-Listenern herumspielen

3.) Sie brauchen keine PublishSubject/PublishRelay von RxJava

Verwenden Sie einfach einen Klick-Listener.

15voto

Wooff Punkte 1073

Wie man es zusammen setzt Beispiel...

  • onClick() Behandlung
  • Cursor - RecyclerView
  • ViewHolder Typen

    public class OrderListCursorAdapter extends CursorRecyclerViewAdapter {
    
    private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
    private static final int ID_VIEW_HOLDER_ACTUAL = 0;
    private static final int ID_VIEW_HOLDER = 1;
    
    public OrderListCursorAdapter(Context context, Cursor cursor) {
        super(context, cursor);
    }
    
    public static class ViewHolderActual extends ViewHolder {
        private static final String TAG = ViewHolderActual.class.getSimpleName();
        protected IViewHolderClick listener;
        protected Button button;
    
        public ViewHolderActual(View v, IViewHolderClick listener) {
            super(v, listener);
            this.listener = listener;
            button = (Button) v.findViewById(R.id.orderList_item_button);
            button.setOnClickListener(this);
        }
    
        public void initFromData(OrderData data) {
            Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
    
        ViewHolder result;
    
        switch (viewType) {
            case ID_VIEW_HOLDER_ACTUAL: {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
                result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
                    @Override
                    public void onCardClick(View view, int position, ViewHolder viewHolder) {
                        Log.d(TAG, ">

15voto

Baker Punkte 17964

Nachverfolgung von MLProgrammer-CiM's ausgezeichnete RxJava-Lösung

Klicks verbrauchen/beobachten

Consumer mClickConsumer = new Consumer() {
        @Override
        public void accept(@NonNull String element) throws Exception {
            Toast.makeText(getApplicationContext(), element +" wurde geklickt", Toast.LENGTH_LONG).show();
        }
    };

ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);

RxJava 2.+

Ändere das Original tl;dr wie folgt:

public Observable getPositionClicks(){
    return onClickSubject;
}

PublishSubject#asObservable() wurde entfernt. Gib einfach das PublishSubject zurück, das ein Observable ist.

13voto

Tomasz Mularczyk Punkte 31078

Meines Verständnisses nach ist es gemäß der Antwort von MLProgrammer-CiM einfach möglich, dies zu tun:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    private ImageView image;
    private TextView title;
    private TextView price;

    public MyViewHolder(View itemView) {
        super(itemView);
        image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
        title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
        price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
        image.setOnClickListener(this);
        title.setOnClickListener(this);
        price.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(context, "Gegenstandsklick Nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X