677 Stimmen

RecyclerView onClick

Hat jemand, der RecyclerView verwendet, einen Weg gefunden, um einen onClickListener für Elemente im RecyclerView festzulegen? Ich dachte daran, für jedes Element einen Listener für jedes Layout festzulegen, aber das scheint etwas zu umständlich zu sein. Ich bin sicher, dass es eine Möglichkeit gibt, dass der RecyclerView auf das onClick-Ereignis hört, aber ich kann es nicht ganz herausfinden.

73voto

Bubunyo Nyavor Punkte 2451

Das ist, was für mich funktioniert hat. Hängen Sie den OnClickListener an den onBindView. Ich weiß nicht wirklich, ob sich dies auf die Leistung auswirkt, aber es scheint gut zu funktionieren mit wenig Code.

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}

55voto

Dies war für mich sehr schwierig, einen Element-Klick-Listener in der Aktivität zu haben und auch einen Klick-Listener für die einzelne Ansicht des Elements zu haben, der nicht den Element-Klick-Listener auslöst. Nachdem ich mit der Antwort von Jacob Tabak herumgespielt habe, respektiere ich seine Antwort für den Element-Klick, wenn keine anderen Berührungsaktionen im Element vorhanden sind.

Ich habe eine benutzerdefinierte OnClickListener-Schnittstelle, die ein Klickereignis für das Element enthält, das die angeklickte Ansicht und die Position des Elements im Adapter enthält. Ich präsentiere eine Instanz davon im Konstruktor (oder es kann mit einem Setter sein) und hänge sie an den Klick-Listener des Ansichtshalterbehälters an.

Ich habe auch einen anderen Klick-Listener im Adapter (kann im Ansichtshalter sein), der den aktuellen Ansichtsklick aus dem Container behandelt.

 public class MyRecyclerAdapter extends RecyclerView.Adapter {

private ArrayList mData;
private OnItemClickListener mOnItemClickListener;

public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}

public MyRecyclerAdapter(ArrayList itemsData,
        OnItemClickListener onItemClickListener) {
    mOnItemClickListener = onItemClickListener;
    this.mData = itemsData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {

    View layoutView = LayoutInflater.from(mContext).inflate(
            R.layout.list_item, parent, false);

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
        }
    });

    viewHlder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do button click work here with
            // mData.get( viewHolder.getAdapterPosition() );
        }
    });

    return viewHolder;
}

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

In der Aktivität müssen Sie den Adapter initialisieren, indem Sie eine Instanz des OnItemClickListener übergeben

public class FeedActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    .....

    MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList(), new OnItemClickListener() {

        @Override
        public void onItemClick(View view, int position) {

            /// Element der Liste wurde angeklickt
        }
    });

    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(mFeedsAdapter);
}

Und mein ViewHolder

public class MyViewHolder extends RecyclerView.ViewHolder {

public Button button;
public View container;

public MyViewHolder(View itemLayoutView) {
    super(itemLayoutView);

    container = itemLayoutView;
    button = (Button) itemLayoutView.findViewById(R.id.button);
}}

43voto

Fifer Sheep Punkte 2800

Dies ist, was ich am Ende brauchte, falls es für jemanden nützlich ist:

public static class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View item) {

        super(item);
        item.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("RecyclerView", "onClick" + getAdapterPosition());
            }
        });

    }
}

Quelle: http://blog.csdn.net/jwzhangjie/article/details/36868515

40voto

Gopal Singh Sirvi Punkte 4413

Ich habe eine gute Lösung für RecyclerView's onItemClickListener für die Elemente und Unterelemente

Schritt 1- Erstelle ein Interface

public interface OnRecyclerViewItemClickListener
{
    /**
     * Aufgerufen, wenn ein Element innerhalb des RecyclerViews oder ein Element innerhalb eines Elements angeklickt wird
     * 
     * @param position
     *            Die Position des Elements
     * @param id
     *            Die ID der Ansicht, die innerhalb des Elements angeklickt wurde oder
     *            -1, wenn das Element selbst angeklickt wurde
     */
    public void onRecyclerViewItemClicked(int position, int id);
}

Schritt 2- Verwende es dann in der Methode onBindViewHolder des Adapters auf folgende Weise

/**
     * Benutzerdefinierte Methode zum Festlegen des Klick-Ereignislisteners für die Elemente und Elemente in den Elementen
     * @param listener OnRecyclerViewItemClickListener 
     */
    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
    {
        this.listener = listener;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position)
    {

        // viewHolder.albumBg.setBackgroundResource(_itemData[position]
        // .getImageUrl());

        viewHolder.albumName.setText(arrayList.get(position).getName());
        viewHolder.artistName.setText(arrayList.get(position).getArtistName());
        String imgUrl = arrayList.get(position).getThumbImageUrl();

        makeImageRequest(imgUrl, viewHolder);
        viewHolder.parentView.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, -1);
            }
        });
        viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, v.getId());
            }
        });

    }

    // Klasse zum Halten eines Verweises auf jedes Element des RecyclerView
    public static class ViewHolder extends RecyclerView.ViewHolder
    {

        public TextView albumName, artistName;
        public ImageView albumIcon, settingButton;
        public LinearLayout parentView;

        public ViewHolder(View itemLayoutView)
        {
            super(itemLayoutView);
            // albumBg = (LinearLayout) itemLayoutView
            // .findViewById(R.id.albumDlbg);
            albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
            artistName = (TextView) itemLayoutView
                    .findViewById(R.id.artistName);
            albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
            parentView = (LinearLayout) itemLayoutView
                    .findViewById(R.id.albumDlbg);
            settingButton = (ImageView) itemLayoutView
                    .findViewById(R.id.settingBtn);
        }

    }

Schritt 3- Finde und richte den RecyclerView in der Aktivität oder im Fragment ein, in dem du dies verwendest

recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);

        lm = new LinearLayoutManager(mActivity);
        lm.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(lm);
        recyclerView.addItemDecoration(
                new HorizontalDividerItemDecoration.Builder(getActivity())
                        .paint(Utils.getPaint()).build());
        PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
                mActivity, true);
        // Adapter setzen
        recyclerView.setAdapter(mAdapter);
        mAdapter.setOnItemClickListener(this);
        // Item Animator auf DefaultAnimator setzen
        recyclerView.setItemAnimator(new DefaultItemAnimator());

Schritt 4- Implementiere schließlich das Interface in der Aktivität oder im Fragment, wo du den RecyclerView verwendest

@Override
    public void onRecyclerViewItemClicked(int position, int id)
    {
        if(id==-1){
            Toast.makeText(mActivity, "vollständiges Element angeklickt", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(mActivity, "Einstellungsschaltfläche angeklickt", Toast.LENGTH_LONG).show();
        }
    }

Aktualisierung für die Kotlin-Sprache Ich habe den Code für Kotlin aktualisiert, in dem nur die gesamte Ansicht einen Klick-Listener hat. Du kannst einen Klick-Listener für Unterelemente einstellen, indem du das Interface und den Code entsprechend dem obigen Java-Code bearbeitest.

Adapter

class RecentPostsAdapter(private val list: MutableList) :
    RecyclerView.Adapter() {
    private lateinit var onItemClickListener: OnItemClickListener

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.listitem_recent_post, parent, false)
        )
    }

    override fun getItemCount(): Int {
        return list.size
    }

    fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
        this.onItemClickListener = onItemClickListener
    }

    private fun getItem(position: Int): Post {
        return list[position]
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
        holder.itemView.setOnClickListener(View.OnClickListener {
            onItemClickListener.onItemClick(
                position
            )
        })
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private var imageView: NetworkImageView? = null
        private var tvTitle: TextView? = null
        private var tvExcerpt: TextView? = null
        private var htmlSpanner: HtmlSpanner = HtmlSpanner()

        init {
            imageView = itemView.findViewById(R.id.niv_post_image)
            tvTitle = itemView.findViewById(R.id.tv_post_title)
            tvExcerpt = itemView.findViewById(R.id.tv_post_excerpt)
        }

        fun bind(post: Post) {
            tvTitle?.text = post.title
            tvExcerpt?.text = htmlSpanner.fromHtml(post.excerpt)
        }
    }

    interface OnItemClickListener {
        fun onItemClick(position: Int)
    }
}

Aktivität oder Fragment

recyclerView = view.findViewById(R.id.rvHomeRecentPosts)
        recyclerView.layoutManager = LinearLayoutManager(view.context)
        list = mutableListOf()
        recentPostsAdapter = RecentPostsAdapter(list)
        recyclerView.adapter = recentPostsAdapter
        recentPostsAdapter.setOnItemClickListener(object:RecentPostsAdapter.OnItemClickListener{
            override fun onItemClick(position: Int) {
                (activity as MainActivity).findNavController(R.id.nav_host_fragment).navigate(R.id.action_nav_home_to_nav_post_detail)
            }

        })

17voto

u2gilles Punkte 7021

Hier ist, was ich gemacht habe. Diese Lösung unterstützt sowohl onClick als auch onLongClick auf sowohl RecyclerView-Elementen als auch Ansichten innerhalb der RecyclerView-Elemente (interne Ansichten).

Ich tagge viewHolder auf den Ansichten meiner Wahl :

public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
    ViewHolder viewHolder = new ViewHolder(itemView);

    itemView.setOnClickListener( this);
    itemView.setOnLongClickListener(this);
    viewHolder.imageIV.setOnClickListener(this);
    viewHolder.imageIV.setOnLongClickListener(this);

    viewHolder.imageIV.setTag(viewHolder);
    itemView.setTag(viewHolder);

    return viewHolder;
}

Und ich benutze holder.getPosition(), um die Position in der onClick() Methode abzurufen (onLongClick ist ähnlich) :

public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    int position = holder.getPosition();

    if (view.getId() == holder.imageIV.getId()){
        Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
    }
}

Eine Variante mit getChildPosition funktioniert auch. Bitte beachten Sie, dass für die internen Ansichten in onClick() verwenden :

int position = recyclerView.getChildPosition((View)view.getParent());

Meiner Meinung nach ist der Vorteil dieser Lösung, dass beim Klicken auf das Bild nur der onclick() Bilder-Listener aufgerufen wird, während bei der Kombination von Jacobs Lösung für eine RecyclerView-Elementansicht und meiner Lösung für interne Ansichten auch der RecyclerView-Elementansicht onclick() aufgerufen wird (beim Klicken auf das Bild).

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