RecyclerView - Belirli bir konumda görünüm elde edin


140

A RecyclerViewve an ile bir etkinliğim var ImageView. RecyclerViewGörüntülerin bir listesini yatay olarak göstermek için kullanıyorum . Ben bir resmi tıkladığınızda aktivitesinde görüntünün büyük resmi göstermelidir. Şimdiye kadar her şey iyi çalışıyor.RecyclerViewImageView

Şimdi ImageButtonsaktivitede iki tane daha var : imageButton_leftve imageButton_right. Tıkladığımda imageButton_left, resimdeki görüntü ImageViewsola dönmeli ve ayrıca resimdeki küçük resim RecyclerViewbu değişikliği yansıtmalıdır. Benzer durum böyle imageButton_right.

Dönebilirim ImageView. Ancak, içindeki küçük resmi nasıl döndürebilirim RecyclerView? ViewHolder'Ları nasıl alabilirim ImageView?

Kod:

Etkinlik XML'si:

<?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>

Etkinlik Kodum:

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);
    }
}

RecyclerView için Özel Adaptörüm:

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());
        }
    }


}

1
Bunu viewHolder yapıcısında yapmalı, görüntünün döndürülmesi gerekip gerekmediğini size söyleyecek bir özellik eklemelisiniz, daha sonra verilerinizdeki bu özelliği değiştirmeli ve recyclerView'i yeniden yüklemek için
notifyDataSetChanged öğesini çağırmalısınız

Cevaplardan herhangi biri sorununuzu çözdü mü?
SMBiggs

ViewHolder'ın performans sorunu için statik olması gerekir. Dış sınıftaki tüm değişkenler yapıcıdan geçirilmelidir.
AppiDevo

@ Scott'ın cevabına ek olarak Buraya
mut tony

Yanıtlar:


149

Sanırım LinearLayoutManagerlisteyi göstermek için a kullanıyorsunuz . Bu güzel bir yöntem findViewByPositionvar

Verilen adaptör konumunu temsil eden görünümü bulur.

Tek ihtiyacınız olan, ilgilendiğiniz ürünün adaptör pozisyonudur.

edit : Paul Woitaschek tarafından yorumlarda belirtildiği gibi , tüm LayoutManagers (yani , vb.) ile çalışmak findViewByPositioniçin bir yöntemdirLayoutManagerStaggeredGridLayoutManager


9
Bu aslında bir yöntem LayoutManagerbu tüm LayoutManager alt sınıfları için çalışacaktır.
Paul Woitaschek

Kaynak koduna baktım. LinearLayoutManger, önyüklemede değilken yedekleme dizisindeki directAccess üzerinden arama yaparken, recyclerView yöntemi her zaman çapraz geçiş yapar. Dolayısıyla bu yöntem muhtemelen daha verimlidir.
NameSpace

Hey @stanO Bu konuda yardıma beni mutlu edebilir stackoverflow.com/questions/49952965/...

3
İade: Görünüm - pozisyon ortaya koydu değilse verilen pozisyon veya null temsil çocuk görünümü ... recyclerview -> çoğu şeyi return null
me_

Bağdaştırıcı listeye eklenene kadar beklemeniz gerektiğini unutmayın, ayrıntılar için aşağıdaki cevabım
Konstantin Konopko

241

Aradığın şey bu .

Ben de bu problemi yaşadım. Ve sizin gibi, cevabı bulmak çok zor. Ancak ViewHolder'ı belirli bir konumdan almanın kolay bir yolu var (muhtemelen Adaptörde çok şey yapacaksınız).

myRecyclerView.findViewHolderForAdapterPosition(pos);

NOT: Görünüm geri dönüştürülmüşse, bu geri döner null. Michael'a önemli ihmalimi çabucak yakaladığı için teşekkürler.


3
Bu tam olarak LayoutManager'da aradığım şeydi
Ed Lee

12
Bu çalışır, ancak ViewHolderbaşvurmaya çalışıyorsanız "geri dönüştürülmüş" ise, geri döner null.
Michael

5
@Michael, iyi yakala! Bu, dışarıdaki herkes için bir uyarı, önce null için test edin (evet, Android'deki diğer her şey gibi)!
SMBiggs

1
Bunu adaptörün içinden yapabilir miyiz?
Mauker

2
@Mauker: Bunu RecyclerView örneğine erişebilen herhangi bir şeyden kullanabilirsiniz.
SMBiggs

26

İsterseniz , ViewHolder özelliğine şu Viewşekilde eriştiğinizden emin olun itemView:myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;


11

Her ikisini de kullanabilirsiniz

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) ve recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition). RecyclerView görünümünün iki tür konum kullandığından emin olun

Adaptör konumu: Bir öğenin adaptördeki konumu. Bu, Adaptörün perspektifinden gelen konumdur. Düzen konumu: Bir öğenin en son düzen hesaplamasındaki konumu. Bu, LayoutManager'ın bakış açısından konumdur. getAdapterPosition()İçin findViewHolderForAdapterPosition(adapterPosition)ve getLayoutPosition()için kullanmalısınız findViewHolderForLayoutPosition(layoutPosition).

Kullanıcının ilk kez tıklayıp tıklamadığını kontrol etmek için geri dönüşüm görünümü adaptöründe ve diğer üye değişkenlerde önceden seçilen öğe konumunu tutmak için bir üye değişkeni alın.

Alt kısımda daha fazla bilgi için örnek kod ve ekran görüntüleri eklenmiştir.

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();    
                }    
            }    
        });    
    }    
}       

} ilk öğe seçildi ikinci öğe seçildi ve önceden seçilen öğenin seçimi kaldırıldı beşinci öğe seçildi ve önceden seçilen öğenin seçimi kaldırıldı


Ve bu tartışmanın tükendiğini düşündüm! Bu sorunu daha ayrıntılı açıkladığınız için teşekkür ederiz.
SMBiggs

2
Burada önceki öğenin rengini değiştirmeye çalışırken başka bir blokta NullPointer istisnasını alıyorum, bu yüzden null denetimi ekledim, şimdi NullPointer istisnası varsa bu bloğa asla girmiyor, bu yüzden önceki öğe rengi asla değişmez. şimdi Recycler görünümümde birden çok renkli öğeye sahip öğeler var. bunu nasıl çözebilirim
Abhilash Reddy

8

ArrayList of ViewHolder yapabilirsiniz:

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

ve ViewHolder (lar) ı listede aşağıdaki gibi saklayın:

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

        myViewHolders.add(position,holder);
}

ve gereksiniminize göre ArrayList'teki diğer ViewHolder'ları ekleyin / kaldırın.


2 gündür geri dönüşümlü sahipler almak için uğraştığınız için teşekkür ederim.
nimi0112

5

Aşağıdakileri kullanarak geri dönüşüm görünümünde belirli bir konum için görünüm elde edebilirsiniz

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

5

" FindViewHolderForAdapterPosition " işlevini kullanabilirsiniz. dönüşümcü görünümünün " yöntemini ve bundan sonra bir viewHolder nesnesi alırsınız ve daha sonra görüntüleyicinizin görünümlerine doğrudan erişebilmeniz için bu görüntüleyiciyi adaptör görüntüleyicinize yazabilirsiniz.

kotlin için örnek kod aşağıdadır

 val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
 val textview=(viewHolder as YourViewHolder).yourTextView

4

Bağdaştırıcı listeye eklenene kadar beklemeniz gerektiğini unutmayın, ardından konuma göre görünüm elde etmeyi deneyebilirsiniz

final int i = 0;
recyclerView.setAdapter(adapter);
recyclerView.post(new Runnable() {
    @Override
    public void run() {
        View view = recyclerView.getLayoutManager().findViewByPosition(i);
    }
});

2
Birden çok öğe eklerseniz bu her zaman işe yaramaz (örneğin, bunları ekleyen bir düğmeye sahipseniz ve hızlıca basarsanız). Runnable'ı gecikmeli olarak eklemelisiniz.
Alex Burdusel

3

Belirli bir recyclerView konumundan Görünüm elde etmek için recyclerView nesnesinde RecyclerView.ViewHolder döndürecek findViewHolderForAdapterPosition (position) öğesini çağırmanız gerekir.

itemView ile döndürülen RecyclerView.ViewHolder nesnesinden belirli bir konumdaki tüm Görünümlere erişebilirsiniz

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

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

1

Bunu da yapabilirsiniz, bu, bir geri dönüşüm görüntüleme konumu öğesini tıkladıktan sonra bir görünümü değiştirmek istediğinizde yardımcı olacaktır

@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");

        }

1

Recycler görünüm listesinden belirli bir görünüm elde etmek için VEYA recycler görünümünün düzenleme metninde hatayı göster.

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 !");
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.