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.
Antworten
Zu viele Anzeigen?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();
}
});
}
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);
}}
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
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)
}
})
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).