RecyclerView - Ruft die Ansicht an einer bestimmten Position ab

139

Ich habe eine Aktivität mit einem RecyclerViewund einem ImageView. Ich verwende die RecyclerView, um eine Liste von Bildern horizontal anzuzeigen. Wenn ich auf einem Bild klicken in der RecyclerViewdie ImageViewin der Tätigkeit sollte ein größeres Bild des Bildes zeigen. Bisher funktioniert alles gut.

Jetzt gibt es zwei weitere ImageButtonsin der Aktivität: imageButton_leftund imageButton_right. Wenn ich auf klicke imageButton_left, sollte das Bild in ImageViewlinks abbiegen und auch das Miniaturbild in RecyclerViewsollte diese Änderung widerspiegeln. Ähnliches gilt für imageButton_right.

Ich kann das drehen ImageView. Aber wie kann ich das Vorschaubild in der drehen RecyclerView? Wie kann ich die bekommen ViewHolder‚s ImageView?

Code:

Aktivitäts-XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/original_image"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:scaleType="fitXY"
            android:src="@drawable/image_not_available_2" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center_horizontal"
            android:orientation="horizontal">


            <ImageButton
                android:id="@+id/imageButton_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="20dp"
                android:background="@drawable/rotate_left_icon" />

            <ImageButton
                android:id="@+id/imageButton_right"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/rotate_right_icon" />

        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Mein Aktivitätscode:

public class SecondActivity extends AppCompatActivity implements IRecyclerViewClickListener {


    RecyclerView mRecyclerView;
    LinearLayoutManager mLayoutManager;
    RecyclerViewAdapter mRecyclerViewAdapter;
    List<String> urls = new ArrayList<String>();
    ImageView mOriginalImageView;
    ImageButton mLeftRotate, mRightRotate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        urls.clear();

        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mLayoutManager = new LinearLayoutManager(this, android.support.v7.widget.LinearLayoutManager.HORIZONTAL, false);
        mLayoutManager.setOrientation(android.support.v7.widget.LinearLayoutManager.HORIZONTAL);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerViewAdapter = new RecyclerViewAdapter(this, urls);
        mRecyclerView.setAdapter(mRecyclerViewAdapter);

        mOriginalImageView = (ImageView) findViewById(R.id.original_image);
        mLeftRotate = (ImageButton) findViewById(R.id.imageButton_left);
        mLeftRotate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOriginalImageView.setRotation(mOriginalImageView.getRotation() - 90);
            }
        });


        mRightRotate = (ImageButton) findViewById(R.id.imageButton_right);
        mRightRotate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOriginalImageView.setRotation(mOriginalImageView.getRotation() + 90);
            }
        });

        Intent intent = getIntent();
        if (intent != null) {

            String portfolio = intent.getStringExtra("portfolio");

            try {

                JSONArray jsonArray = new JSONArray(portfolio);

                for (int i = 0; i < jsonArray.length(); i++) {

                    JSONObject jsonObject = jsonArray.getJSONObject(i);

                    String url = jsonObject.getString("url");
                    urls.add(url);
                }

                Log.d(Const.DEBUG, "URLs: " + urls.toString());

                mRecyclerViewAdapter.notifyDataSetChanged();

            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }


    @Override
    public void onItemClick(int position) {
        Picasso.with(this).load(urls.get(position)).into(mOriginalImageView);
    }
}

Mein benutzerdefinierter Adapter für RecyclerView:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    Context context;
    List<String> mUrls = new ArrayList<String>();

    IRecyclerViewClickListener mIRecyclerViewClickListener;

    public int position;

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }



    public RecyclerViewAdapter(Context context, List<String> urls) {
        this.context = context;
        this.mUrls.clear();
        this.mUrls = urls;

        Log.d(Const.DEBUG, "Urls Size: " + urls.size());
        Log.d(Const.DEBUG, urls.toString());

        if (context instanceof IRecyclerViewClickListener)
            mIRecyclerViewClickListener = (IRecyclerViewClickListener) context;
        else
            Log.d(Const.DEBUG, "Implement IRecyclerViewClickListener in Activity");
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_horizontal_recyclerview, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Picasso.with(context).load(mUrls.get(position)).into(holder.mImageView);
    }

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


    public void rotateThumbnail() {


    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        public ImageView mImageView;
        public View v;

        public ViewHolder(View v) {
            super(v);
            v.setTag(getAdapterPosition());
            v.setOnClickListener(this);
            this.mImageView = (ImageView) v.findViewById(R.id.image);
        }

        @Override
        public void onClick(View v) {
            this.v = v;
            mIRecyclerViewClickListener.onItemClick(getAdapterPosition());
        }
    }


}
Vamsi Challa
quelle
1
Sie sollten es in Ihrem viewHolder-Konstruktor erstellen, eine Eigenschaft hinzufügen, die Ihnen sagt, ob das Bild gedreht werden muss, dann einfach diese Eigenschaft in Ihren Daten ändern und notifyDataSetChanged aufrufen, um die recyclerView neu zu laden
Nanoc
Löst eine der Antworten Ihr Problem?
Scott Biggs
ViewHolder sollte aus Leistungsgründen statisch sein. Alle Variablen aus der äußeren Klasse sollten durch den Konstruktor übergeben werden.
AppiDevo
Als Ergänzung zu @ Scotts Antwort Klicken Sie hier
Mutony

Antworten:

149

Ich nehme an, Sie verwenden a LinearLayoutManager, um die Liste anzuzeigen. Es hat eine schöne Methode namens findViewByPositiondas

Findet die Ansicht, die die angegebene Adapterposition darstellt.

Sie benötigen lediglich die Adapterposition des Artikels, an dem Sie interessiert sind.

edit : wie von Paul Woitaschek in den Kommentaren erwähnt, findViewByPositionist eine Methode, LayoutManagerdamit es mit allen LayoutManagern (dh StaggeredGridLayoutManagerusw.) funktioniert .

stan0
quelle
9
Das ist eigentlich eine Methode der, LayoutManagerso dass dies für alle LayoutManager-Unterklassen funktioniert.
Paul Woitaschek
Sah den Quellcode an. LinearLayoutManger sucht über directAccess auf dem Backing-Array, wenn es sich nicht im Prelayout befindet, während die recyclerView-Methode immer eine Durchquerung durchführt. Diese Methode ist also wahrscheinlich effizienter.
NameSpace
Hey @stanO können Sie mir bitte mit diesem stackoverflow.com/questions/49952965/…
3
Rückgabe: Ansicht - Die untergeordnete Ansicht, die die angegebene Position oder null darstellt, wenn die Position nicht angelegt ist ... recyclerview -> die meisten Dinge geben null zurück
me_
Denken Sie daran, dass Sie warten müssen, bis der Adapter zur Liste hinzugefügt wird.
Weitere
241

Das ist was Sie suchen .

Ich hatte auch dieses Problem. Und wie Sie ist die Antwort sehr schwer zu finden. Es gibt jedoch eine einfache Möglichkeit, den ViewHolder von einer bestimmten Position aus abzurufen (etwas, das Sie im Adapter wahrscheinlich häufig tun werden).

myRecyclerView.findViewHolderForAdapterPosition(pos);

HINWEIS: Wenn die Ansicht recycelt wurde, wird diese zurückgegeben null. Vielen Dank an Michael, der meine wichtige Lücke schnell erkannt hat.

Scott Biggs
quelle
3
Dies ist genau das, wonach ich im LayoutManager gesucht habe
Ed Lee
12
Dies funktioniert jedoch, wenn das, auf das ViewHolderSie verweisen möchten, "recycelt" wurde, wird es zurückgegeben null.
Michael
5
@ Michael, guter Fang! Das ist eine Warnung an alle da draußen, teste zuerst auf Null (ja, wie alles andere in Android)!
Scott Biggs
1
Können wir dies aus dem Adapter heraus tun?
Mauker
2
@Mauker: Sie können dies von jedem Ort aus verwenden, der auf die RecyclerView-Instanz zugreifen kann.
Scott Biggs
27

Wenn Sie das möchten View, stellen Sie sicher, dass itemViewSie wie folgt auf die Eigenschaft des ViewHolder zugreifen:myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;

Horatio
quelle
11

Sie können beide verwenden

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) und recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition). Stellen Sie sicher, dass die RecyclerView-Ansicht zwei Arten von Positionen verwendet

Adapterposition: Position eines Elements im Adapter. Dies ist die Position aus Sicht des Adapters. Layoutposition: Position eines Elements in der letzten Layoutberechnung. Dies ist die Position aus Sicht des LayoutManagers. Sie sollten getAdapterPosition()für findViewHolderForAdapterPosition(adapterPosition)und getLayoutPosition()für verwenden findViewHolderForLayoutPosition(layoutPosition).

Nehmen Sie eine Mitgliedsvariable, um die zuvor ausgewählte Elementposition im Recyclerview-Adapter zu halten, und eine andere Mitgliedsvariable, um zu überprüfen, ob der Benutzer zum ersten Mal klickt oder nicht.

Beispielcode und Screenshots finden Sie unten für weitere Informationen.

public class MainActivity extends AppCompatActivity {     

private RecyclerView mRecyclerList = null;    
private RecyclerAdapter adapter = null;    

@Override    
protected void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);    
    setContentView(R.layout.activity_main);    

    mRecyclerList = (RecyclerView) findViewById(R.id.recyclerList);    
}    

@Override    
protected void onStart() {    
    RecyclerView.LayoutManager layoutManager = null;    
    String[] daysArray = new String[15];    
    String[] datesArray = new String[15];    

    super.onStart();    
    for (int i = 0; i < daysArray.length; i++){    
        daysArray[i] = "Sunday";    
        datesArray[i] = "12 Feb 2017";    
    }    

    adapter = new RecyclerAdapter(mRecyclerList, daysArray, datesArray);    
    layoutManager = new LinearLayoutManager(MainActivity.this);    
    mRecyclerList.setAdapter(adapter);    
    mRecyclerList.setLayoutManager(layoutManager);    
}    
}    


public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyCardViewHolder>{          

private final String TAG = "RecyclerAdapter";        
private Context mContext = null;        
private TextView mDaysTxt = null, mDateTxt = null;    
private LinearLayout mDateContainerLayout = null;    
private String[] daysArray = null, datesArray = null;    
private RecyclerView mRecyclerList = null;    
private int previousPosition = 0;    
private boolean flagFirstItemSelected = false;    

public RecyclerAdapter(RecyclerView mRecyclerList, String[] daysArray, String[] datesArray){    
    this.mRecyclerList = mRecyclerList;    
    this.daysArray = daysArray;    
    this.datesArray = datesArray;    
}    

@Override    
public MyCardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    
    LayoutInflater layoutInflater = null;    
    View view = null;    
    MyCardViewHolder cardViewHolder = null;    
    mContext = parent.getContext();    
    layoutInflater = LayoutInflater.from(mContext);    
    view = layoutInflater.inflate(R.layout.date_card_row, parent, false);    
    cardViewHolder = new MyCardViewHolder(view);    
    return cardViewHolder;    
}    

@Override    
public void onBindViewHolder(MyCardViewHolder holder, final int position) {    
    mDaysTxt = holder.mDaysTxt;    
    mDateTxt = holder.mDateTxt;    
    mDateContainerLayout = holder.mDateContainerLayout;    

    mDaysTxt.setText(daysArray[position]);    
    mDateTxt.setText(datesArray[position]);    

    if (!flagFirstItemSelected){    
        mDateContainerLayout.setBackgroundColor(Color.GREEN);    
        flagFirstItemSelected = true;    
    }else {    
        mDateContainerLayout.setBackground(null);    
    }    
}    

@Override    
public int getItemCount() {    
    return daysArray.length;    
}    

class MyCardViewHolder extends RecyclerView.ViewHolder{    
    TextView mDaysTxt = null, mDateTxt = null;    
    LinearLayout mDateContainerLayout = null;    
    LinearLayout linearLayout = null;    
    View view = null;    
    MyCardViewHolder myCardViewHolder = null;    

    public MyCardViewHolder(View itemView) {    
        super(itemView);    
        mDaysTxt = (TextView) itemView.findViewById(R.id.daysTxt);    
        mDateTxt = (TextView) itemView.findViewById(R.id.dateTxt);    
        mDateContainerLayout = (LinearLayout) itemView.findViewById(R.id.dateContainerLayout);    

        mDateContainerLayout.setOnClickListener(new View.OnClickListener() {    
            @Override    
            public void onClick(View v) {    
                LinearLayout linearLayout = null;    
                View view = null;    

                if (getAdapterPosition() == previousPosition){    
                    view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackgroundColor(Color.GREEN);    
                    previousPosition = getAdapterPosition();    

                }else {    
                    view = mRecyclerList.findViewHolderForAdapterPosition(previousPosition).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackground(null);    

                    view = mRecyclerList.findViewHolderForAdapterPosition(getAdapterPosition()).itemView;    
                    linearLayout = (LinearLayout) view.findViewById(R.id.dateContainerLayout);    
                    linearLayout.setBackgroundColor(Color.GREEN);    
                    previousPosition = getAdapterPosition();    
                }    
            }    
        });    
    }    
}       

}} erstes ausgewähltes Element Das zweite ausgewählte Element und das zuvor ausgewählte Element werden nicht ausgewählt Das fünfte ausgewählte Element und das zuvor ausgewählte Element werden nicht ausgewählt

Vikash Kumar Tiwari
quelle
Und ich fand diese Diskussion erschöpft! Vielen Dank für die weitere Klärung dieses Problems.
Scott Biggs
2
Hier erhalte ich die NullPointer-Ausnahme im else-Block, wenn ich versuche, die Farbe des vorherigen Elements zu ändern. Daher habe ich die Null-Prüfung hinzugefügt. Jetzt wird sie nie in diesen Block eingegeben, wenn sie eine NullPointer-Ausnahme hat, also die Farbe des vorherigen Elements wird nie geändert. Jetzt enthält meine Recycler-Ansicht Elemente mit mehreren farbigen Elementen. Wie löse ich das
Abhilash Reddy
8

Sie können ArrayList von ViewHolder erstellen:

 ArrayList<MyViewHolder> myViewHolders = new ArrayList<>();
 ArrayList<MyViewHolder> myViewHolders2 = new ArrayList<>();

und alle speichern ViewHolder (s) in der Liste wie folgt:

 @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        final String str = arrayList.get(position);

        myViewHolders.add(position,holder);
}

und fügen Sie gemäß Ihrer Anforderung einen anderen ViewHolder in der ArrayList hinzu / entfernen Sie ihn.

Tarun Umath
quelle
Vielen Dank, dass ich seit 2 Tagen Probleme habe, recycelte Halter zu bekommen.
nimi0112
5

Mithilfe der folgenden Informationen können Sie eine Ansicht für eine bestimmte Position in einer Recyclingansicht abrufen

int position = 2;
RecyclerView.ViewHolder viewHolder = recyclerview.findViewHolderForItemId(position);
View view = viewHolder.itemView;
ImageView imageView = (ImageView)view.findViewById(R.id.imageView);
Sonntag G Akinsete
quelle
5

Sie können einfach die Methode " findViewHolderForAdapterPosition " der Recycler-Ansicht verwenden, und Sie erhalten daraus ein viewHolder-Objekt. Geben Sie diesen Ansichtsinhaber dann in Ihren Adapter-Ansichtsinhaber ein, damit Sie direkt auf die Ansichten Ihres Ansichtsinhabers zugreifen können

Es folgt der Beispielcode für Kotlin

 val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
 val textview=(viewHolder as YourViewHolder).yourTextView
Mayank Sharma
quelle
4

Denken Sie daran, dass Sie warten müssen, bis der Adapter zur Liste hinzugefügt wird. Dann können Sie versuchen, die Ansicht nach Position zu erhalten

final int i = 0;
recyclerView.setAdapter(adapter);
recyclerView.post(new Runnable() {
    @Override
    public void run() {
        View view = recyclerView.getLayoutManager().findViewByPosition(i);
    }
});
Konstantin Konopko
quelle
2
Dies funktioniert nicht immer, wenn Sie mehrere Elemente hinzufügen (dh wenn Sie eine Schaltfläche haben, mit der Sie diese hinzufügen und schnell drücken können). Sie sollten die ausführbare Datei mit Verzögerung hinzufügen.
Alex Burdusel
3

Um eine Ansicht von einer bestimmten Position von recyclerView abzurufen, müssen Sie findViewHolderForAdapterPosition (position) für das recyclerView-Objekt aufrufen, das RecyclerView.ViewHolder zurückgibt

Über das zurückgegebene RecyclerView.ViewHolder-Objekt mit itemView können Sie auf alle Ansichten an dieser bestimmten Position zugreifen

RecyclerView.ViewHolder rv_view = recyclerView.findViewHolderForAdapterPosition(position);

ImageView iv_wish = rv_view.itemView.findViewById(R.id.iv_item);
Tushar
quelle
1

Sie können dies auch tun. Dies ist hilfreich, wenn Sie eine Ansicht ändern möchten, nachdem Sie auf ein Positionselement für die Recyclingansicht geklickt haben

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

            View v =  rv_notifications.getChildViewHolder(view).itemView;
            TextView content = v.findViewById(R.id.tv_content);
            content.setText("Helloo");

        }
Mut tony
quelle
1

Um eine bestimmte Ansicht aus der Liste der Recycler-Ansichten zu erhalten, ODER zeigen Sie einen Fehler im Text der Recycler-Ansicht an.

private void popupErrorMessageAtPosition(int itemPosition) {

    RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(itemPosition);
    View view = viewHolder.itemView;
    EditText etDesc = (EditText) view.findViewById(R.id.et_description);
    etDesc.setError("Error message here !");
}
Chirag Prajapati
quelle