Ich ersetze meine ListView
durch RecyclerView
, die Liste zeigt ok, aber ich würde gerne wissen, wie man ein geklicktes Element und seine Position erhält, ähnlich der Methode OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id)
, die wir in ListView
verwenden.
Danke für die Ideen!
Basierend auf dem Link: Warum hat RecyclerView keinen onItemClickListener ()? und Wie unterscheidet sich RecyclerView von Listview? , und auch @ Duncans allgemeine Idee, ich gebe meine Lösung hier:
Definieren Sie eine Schnittstelle RecyclerViewClickListener
, um die Nachricht vom Adapter an Activity
Fragment
ZU ÜBERGEBEN:
public interface RecyclerViewClickListener {
public void recyclerViewListClicked(View v, int position);
}
IMPLEMENTIEREN SIE IN Activity
/Fragment
DIE SCHNITTSTELLE UND ÜBERGEBEN SIE DEN LISTENER AN DEN ADAPTER:
@Override
public void recyclerViewListClicked(View v, int position){... ...}
//set up adapter and pass clicked listener this
myAdapter = new MyRecyclerViewAdapter(context, this);
IN Adapter
UND 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());
}
}
}
NACH DEM TESTEN FUNKTIONIERT ES GUT.
[_/_ UPDATE]
Seit API 22 ist RecyclerView.ViewHoler.getPosition()
veraltet, also stattdessen mit 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();
}
}
});
}
}
}
Hier ist ein Beispiel, um einen Click-Listener festzulegen.
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;
}
}
}
Fügen Sie diesen Code dort ein, wo Sie die Recycler-Ansicht in der Aktivität definieren.
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();
}
})
);
Dann machen Sie eine separate Klasse und geben Sie diesen Code ein:
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) {
}
}
Wenn Sie das Click-Ereignis von recycle-View aus Aktivität/Fragment anstelle des Adapters verwenden möchten, können Sie auch die folgende Abkürzung verwenden.
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;
}
});
Sie können auch andere Möglichkeiten verwenden, z. B. die Benutzeroberfläche
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) {
}
}
)
);
Verwenden Sie den folgenden Code: -
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 bietet keine solche Methode.
Zum Verwalten von Klickereignissen in RecyclerView habe ich onClickListener in meinem Adapter implementiert, wenn ich den ViewHolder binde: In meinem ViewHolder verweise ich auf die Stammansicht (wie bei ImageViews, TextViews usw.) und beim Binden the viewHolder Ich setze ein Tag mit Informationen, die ich für den Klick (zB Position) und einen Clicklistener verwenden muss
java-Datei mit dem folgenden Code erstellen
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.getChildLayoutPosition(childView));
return true;
}
return false;
}
@Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
und verwenden Sie einfach den Listener für Ihr RecyclerView-Objekt.
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) {
// TODO Handle item click
}
}));
Verwenden Sie getLayoutPosition () in Ihrer Java-Methode für Ihre benutzerdefinierte Schnittstelle. Dadurch wird die ausgewählte Position eines Elements zurückgegeben
https://becody.com/get-clicked-item-and-its-position-in-recyclerview/
Jedes Mal verwende ich einen anderen Ansatz. Personen scheinen eine Position zu speichern oder eine Position in einer Ansicht zu erhalten, anstatt einen Verweis auf ein Objekt zu speichern, das von ViewHolder angezeigt wird.
Ich verwende diese Methode stattdessen und speichere sie einfach in ViewHolder, wenn onBindViewHolder () aufgerufen wird, und setze den Verweis auf null in onViewRecycled ().
Jedes Mal, wenn ViewHolder unsichtbar wird, wird es recycelt. Dies wirkt sich also nicht auf den großen Speicherverbrauch aus.
@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;
...
}
Vom Designer aus können Sie die onClick
-Eigenschaft des listItem auf eine Methode festlegen, die mit einem einzelnen Parameter definiert ist. Ich habe eine Beispielmethode, die unten definiert ist. Die Methode getAdapterPosition gibt Ihnen den Index des ausgewählten listItem.
public void exampleOnClickMethod(View view){
myRecyclerView.getChildViewHolder(view).getAdapterPosition());
}
Informationen zum Einrichten einer RecyclerView finden Sie in der Dokumentation hier: https://developer.Android.com/guide/topics/ui/layout/recyclerview
Hier ist der einfachste und einfachste Weg, um die Position des angeklickten Elements zu ermitteln:
Ich hatte auch das gleiche Problem.
Ich wollte die Position des angeklickten/ausgewählten Elements von RecyclerView () ermitteln und einige spezifische Vorgänge für dieses bestimmte Element ausführen.
die getAdapterPosition () -Methode wirkt wie ein Zauber für diese Art von Sachen. Ich fand diese Methode nach einem langen Tag der Forschung und nachdem ich zahlreiche andere Methoden ausprobiert hatte.
int position = getAdapterPosition();
Toast.makeText(this, "Position is: "+position, Toast.LENGTH_SHORT).show();
Sie müssen keine zusätzliche Methode verwenden. Erstellen Sie einfach eine globale Variable mit dem Namen 'position' und initialisieren Sie sie mit getAdapterPosition () in einer der Hauptmethoden des Adapters (Klasse oder ähnliches).
Hier ist eine kurze Dokumentation aus diesem link .
getAdapterPosition hinzugefügt in Version 22.1.0 int getAdapterPosition () Gibt die Adapterposition des durch diesen ViewHolder dargestellten Objekts zurück. Beachten Sie, dass dies möglicherweise von getLayoutPosition () abweicht, wenn Adapteraktualisierungen ausstehen, ein neuer Layout-Durchlauf jedoch noch nicht erfolgt ist . RecyclerView verarbeitet bis zum nächsten Layout-Durchlauf keine Adapteraktualisierungen. Dies kann zu vorübergehenden Inkonsistenzen zwischen dem, was der Benutzer auf dem Bildschirm sieht, und dem Inhalt des Adapters führen. Diese Inkonsistenz ist nicht wichtig, da sie weniger als 16 ms beträgt. Es kann jedoch ein Problem sein, wenn Sie die ViewHolder-Position für den Zugriff auf den Adapter verwenden möchten. In einigen Fällen müssen Sie möglicherweise die genaue Adapterposition ermitteln, um einige Aktionen als Reaktion auf Benutzerereignisse auszuführen. In diesem Fall sollten Sie diese Methode verwenden, die die Adapterposition des ViewHolder berechnet.
Freue mich zu helfen. Fühlen Sie sich frei, um Zweifel zu fragen.
Kurze Erweiterung für Kotlin
Die Methode gibt die absolute Position aller Elemente zurück (nicht die Position nur sichtbarer Elemente).
fun RecyclerView.getChildPositionAt(x: Float, y: Float): Int {
return getChildAdapterPosition(findChildViewUnder(x, y))
}
Und Verwendung
val position = recyclerView.getChildPositionAt(event.x, event.y)
//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) {
}
});
}
Versuchen Sie es auf diese Weise
Adapterklasse:
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);
}
});
}
}
}
In Ihrer Aktivität oder im Fragment:
ContentAdapter adapter = new ContentAdapter(itemList, this);
Hinweis: Implementieren Sie den OnItemClickListener basierend auf dem von Ihnen angegebenen Kontext in Aktivitäts- oder Fragment- und Overide-Methoden.