Zugriff auf ein ViewHolder, direkt aus der RecyclerView, durch position

Ich habe eine RecyclerView, das zeigt eine Serie von Ansichten, abgeleitet aus einer Datenbank. Ich wünschte, um zu bestätigen, dass der Benutzer ausgewählt hat, eine der Ansichten, die durch Hervorhebung seiner Kanten, und ich habe ihm gelungen. Wenn der Benutzer die Erlöse wählen Sie eine neue option, ich möchte zu löschen, die Markierung auf der ursprünglichen Auswahl. Dies ist, wo ich lief in ein wenig Mühe.

Das erste highlight war ohne Probleme, als ich es Tat, intern. Allerdings weiß ich nicht, wie Sie auf die Vorherige Ansicht mit nur die adapter-position. Ich habe die Suche StackOverflow für über eine Stunde jetzt, so kann ich nicht finden, viel zu gehen in der Android-API, oder über google. Viele Anwender scheinen zu Fragen, ähnliche Fragen, aber letztendlich subtile Unterschiede erlischt jegliche sinnvolle Antworten.

In meinem ViewHolder ist, das eine innere public class meiner RecyclerView habe ich eine OnClickListener wie folgt:

@Override
    public void onClick(View view) {
        if(!selected) {
            selected = true;
            view.setBackgroundResource(R.drawable.default_selection_background);
        } else {
            selected = false;
            view.setBackgroundResource(0);
        }

        UpdateSelected(getAdapterPosition());
    }

Diese Punkte zurück zu meinem RecyclerView, und ehrlich gesagt, bin ich noch hinzufügen, funktionierenden code zu meinem UpdateSelected(int position) Methode.

Wenn es hilft, ich habe die Absicht, es funktioniert so:

void UpdateSelected(int position) {
    if(position != currentlySelected) {
        ViewHolder[currentlySelected].Deselect();
    }
}

public class ViewHolder extends RecyclerView.ViewHolder {
    ...

    public void Deselect() {
        //and from here, I can go on as normal.
    }
}

Habe ich bemerkt, Benutzer, Beratung und andere zu verwenden getLayoutPosition() zum ableiten der position, für die UI-Zwecke, es sei denn, dass Sie ausdrücklich wünschen, um weiter zu arbeiten mit den internen Daten, die ist, was ich zu tun beabsichtigen.

Wie kann ich den Zugriff auf ein bestimmtes ViewHolder von meinem RecyclerView, mit seiner position?

InformationsquelleAutor Gnemlock | 2016-10-03



3 Replies
  1. 1

    Konnten Sie so etwas tun.

    Den adapter ein , erstellen Sie ein member-variable, die wird verfolgen die ausgewählte position.

     int selectedPosition = -1; //-1 some default value for nothing selected

    Dann in Ihre onBindViewHolder des recycler-Ansicht-adapter

      int backgroundRes = (position == selectedPosition)? R.drawable.default_selection_background : 0;
      view.setBackgroundResource(backgroundRes);

    Schließlich in onClick Ihrer viewholder

     @Override
     public void onClick(View view) {
       selectedPosition = getAdapterPosition();
       notifyDataSetChanged();
     }
    • Genial! funktioniert wie ein Charme. Es einzige änderung die ich machen musste war in der onBindViewHolder, die nicht sofort Zugang zu view. Ich benutzte einfach viewHolder.itemView.setBackgroundResource(backgroundRes). Für den Punkt der Effizienz bin ich auch nur notifyItemChanged auf previousSelection und currentSelection, aber ich danke Ihnen so sehr.
    • Ich bin auch vor dem gleichen Problem. also versuche ich, die Lösung aber nicht in meinem Fall. @Gnemlock
    • Ich habe gerade stolperte über diese Antwort, und während Sie gut, ich würde vorschlagen, ändern notifyDataSetChanged() zu notifyItemChanged(selectedPosition). Es ist gute Praxis, um zu vermeiden, fordern notifyDataSetChanged() wenn Sie können feststellen, dass der adapter genau die Ansichten aktualisiert werden müssen.
  2. 1

    Können Sie auf den viewholder, indem es die position von recyclerview

    Hier ist meine Umsetzung

    recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this,
                    recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                   /*your coding */
                }
    
                @Override
                public void onItemLongClick(View view, int position) {
    
                }
    
            }));

    und erstellen Sie die Klasse

    public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    
        private OnItemClickListener mListener;
        private GestureDetector mGestureDetector;
        public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
            mListener = listener;
    
            mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    return true;
                }
                @Override
                public void onLongPress(MotionEvent e) {
                    View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
    
                    if (childView != null && mListener != null) {
                        mListener.onItemLongClick(childView, recyclerView.getChildPosition(childView));
                    }
                }
            });
        }
    
        @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.getChildPosition(childView));
            }
            return false;
        }
    
        @Override
        public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
        }
    
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    
        }
        public interface OnItemClickListener {
            void onItemClick(View view, int position);
            void onItemLongClick(View view, int position);
        }
    }
  3. 0

    Anstatt zu tauschen das Hintergrundbild manuell, können Sie stattdessen markieren Sie die view als selektiert oder nicht, und haben Android-ändern Sie den hintergrund mit drawable-Selektoren.

    res/drawable/background.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:state_selected="true" android:drawable="@drawable/default_selection_background" />
      <item android:drawable="@null" />
    </selector>

    background.xml wäre als android:background in Ihrem Element-layout XML.

    Dann in Ihre onBindViewHolder(ViewHolder holder, int position) aktualisieren Sie den Status des Android-Ansicht:

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        boolean isSelected = position == selectedPosition;
        holder.itemView.setSelected(isSelected);
    }

    Für mich, ich würde lieber einen Adapter, der war dümmer und hatte weniger Logik. Sie können dies, indem Sie eine Liste der ViewModels (Daten-Klassen, die das darstellen, was Sie zeigen in der Ansicht – nicht mehr, nicht weniger), wo eine der Eigenschaften, könnte sein, das ausgewählte flag (in jedem ViewModel).

    Wenn der Benutzer selektiert oder deselektiert eine Ansicht, eine callback-Probleme ein update auf die Moderatorin, die aktualisiert dann den adapter, und benachrichtigt den adapter, die Positionen wurden aktualisiert. Dies würde bedeuten, halten das aktuell ausgewählte Element (vorzugsweise ID, aber speichern könnte ViewModel oder position), in der Moderator so können Sie diese aktualisieren.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.