RecyclerView - Dapatkan tampilan pada posisi tertentu

140

Saya memiliki aktivitas dengan a RecyclerViewdan ImageView. Saya menggunakan ini RecyclerViewuntuk menampilkan daftar gambar secara horizontal. Ketika saya klik pada gambar di RecyclerViewdalam ImageViewaktivitas harus menunjukkan gambaran yang lebih besar dari gambar. Sejauh ini semuanya bekerja dengan baik.

Sekarang ada dua ImageButtonskegiatan lagi: imageButton_leftdan imageButton_right. Ketika saya mengklik imageButton_left, gambar di ImageViewharus belok kiri dan juga, thumbnail di RecyclerViewharus mencerminkan perubahan ini. Serupa halnya dengan imageButton_right.

Saya dapat memutar ImageView. Tapi, bagaimana saya bisa memutar thumbnail di RecyclerView? Bagaimana saya bisa mendapatkan ViewHolderitu ImageView?

Kode:

XML Kegiatan:

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

Kode Aktivitas Saya:

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

Adaptor Kustom Saya untuk 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
sumber
1
Anda harus membuatnya di konstruktor viewHolder Anda, tambahkan properti yang akan memberi tahu Anda jika gambar perlu diputar, kemudian cukup ubah properti itu pada data Anda dan panggil notifyDataSetChanged untuk membuat recyclerView ulang
Nanoc
Apakah ada jawaban yang memecahkan masalah Anda?
Scott Biggs
ViewHolder harus statis untuk masalah kinerja. Semua variabel dari kelas luar harus dilewatkan melalui konstruktor.
AppiDevo
Sebagai tambahan untuk jawaban @ Scott. Klik di sini
mut tony

Jawaban:

149

Saya kira Anda menggunakan a LinearLayoutManageruntuk menampilkan daftar. Ini memiliki metode yang bagus yang disebut findViewByPositionitu

Menemukan tampilan yang mewakili posisi adaptor yang diberikan.

Yang Anda butuhkan hanyalah posisi adaptor dari item yang Anda minati.

sunting : seperti yang dicatat oleh Paul Woitaschek dalam komentar, findViewByPositionadalah metode untuk LayoutManagerbekerja dengan semua LayoutManagers (yaitu StaggeredGridLayoutManager, dll.)

st0
sumber
9
Itu sebenarnya metode yang LayoutManagerjadi ini akan bekerja untuk semua subclass LayoutManager.
Paul Woitaschek
Tampak pada kode sumber. LinearLayoutManger mencari melalui directAccess pada backing array ketika tidak di prelayout, sedangkan metode recyclerView selalu melakukan traversal. Jadi metode ini kemungkinan lebih efisien.
NameSpace
Hei @stanO, tolong bantu saya dengan stackoverflow.com/questions/49952965/…
3
Returns: View - Tampilan anak yang mewakili posisi yang diberikan atau null jika posisi tersebut tidak diletakkan ... recyclerview -> kebanyakan hal mengembalikan null
me_
Ingatlah bahwa Anda harus menunggu sampai adaptor akan ditambahkan ke daftar, lihat jawaban saya di bawah ini untuk perincian
Konstantin Konopko
241

Ini yang kamu cari .

Saya punya masalah ini juga. Dan seperti Anda, jawabannya sangat sulit ditemukan. Tetapi ADA cara mudah untuk mendapatkan ViewHolder dari posisi tertentu (sesuatu yang mungkin akan Anda lakukan banyak di Adapter).

myRecyclerView.findViewHolderForAdapterPosition(pos);

CATATAN: Jika Tampilan telah didaur ulang, ini akan kembali null. Terima kasih kepada Michael karena cepat menangkap kelalaian penting saya.

Scott Biggs
sumber
3
Ini persis apa yang saya cari di Manajer Layout
Ed Lee
12
Ini berfungsi, namun, jika ViewHolderAnda mencoba referensi "didaur ulang", itu akan kembali null.
Michael
5
@Michael, tangkapan bagus! Itu peringatan bagi Anda semua di luar sana, uji null terlebih dahulu (ya, seperti yang lainnya di Android)!
Scott Biggs
1
Bisakah kita melakukan ini dari dalam adaptor?
Mauker
2
@ MAuker: Anda dapat menggunakan ini dari apa pun yang dapat mengakses instance RecyclerView.
Scott Biggs
26

Jika Anda menginginkannya View, pastikan untuk mengakses itemViewproperti ViewHolder seperti:myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;

Horatio
sumber
11

Anda bisa menggunakan keduanya

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) dan recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition). Pastikan tampilan RecyclerView menggunakan dua jenis posisi

Posisi adaptor: Posisi item dalam adaptor. Ini adalah posisi dari sudut pandang Adaptor. Posisi tata letak: Posisi item dalam perhitungan tata letak terbaru. Ini adalah posisi dari perspektif LayoutManager. Anda harus menggunakan getAdapterPosition()untuk findViewHolderForAdapterPosition(adapterPosition)dan getLayoutPosition()untukfindViewHolderForLayoutPosition(layoutPosition) .

Ambil variabel anggota untuk menahan posisi item yang sebelumnya dipilih dalam adaptor recyclerview dan variabel anggota lainnya untuk memeriksa apakah pengguna mengklik pertama kali atau tidak.

Kode contoh dan tangkapan layar dilampirkan untuk informasi lebih lanjut di bagian bawah.

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

} elemen pertama yang dipilih elemen kedua yang dipilih dan item yang sebelumnya dipilih menjadi tidak dipilih elemen kelima yang dipilih dan item yang sebelumnya dipilih menjadi tidak dipilih

Vikash Kumar Tiwari
sumber
Dan saya pikir diskusi ini sudah habis! Terima kasih telah mengklarifikasi masalah ini lebih lanjut.
Scott Biggs
2
Di sini saya mendapatkan pengecualian NullPointer di blok lain ketika saya mencoba mengubah warna item sebelumnya, jadi saya menambahkan centang nol, sekarang tidak pernah masuk ke blok itu jika memiliki pengecualian NullPointer, jadi warna item sebelumnya tidak pernah berubah. sekarang tampilan Pendaur Ulang saya memiliki item dengan beberapa item berwarna. bagaimana cara mengatasi ini
Abhilash Reddy
8

Anda dapat membuat ArrayList dari ViewHolder:

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

dan, semua menyimpan ViewHolder (s) dalam daftar seperti:

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

        myViewHolders.add(position,holder);
}

dan tambahkan / hapus ViewHolder lain di ArrayList sesuai kebutuhan Anda.

Tarun Umath
sumber
Terima kasih, saya telah berjuang untuk mendapatkan pemegang daur ulang selama 2 hari.
nimi0112
5

Anda bisa mendapatkan tampilan untuk posisi tertentu pada recyclerview menggunakan yang berikut ini

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

Anda cukup menggunakan metode " findViewHolderForAdapterPosition " dari tampilan pendaur ulang dan Anda akan mendapatkan objek viewHolder dari itu lalu ketik penampil itu ke penampil adaptor Anda sehingga Anda dapat langsung mengakses pandangan penampil Anda

berikut ini adalah kode sampel untuk kotlin

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

Ingatlah bahwa Anda harus menunggu sampai adaptor akan ditambahkan ke daftar, maka Anda dapat mencoba untuk mendapatkan tampilan berdasarkan posisi

final int i = 0;
recyclerView.setAdapter(adapter);
recyclerView.post(new Runnable() {
    @Override
    public void run() {
        View view = recyclerView.getLayoutManager().findViewByPosition(i);
    }
});
Konstantin Konopko
sumber
2
Ini tidak selalu berfungsi jika Anda menambahkan beberapa item (yaitu: jika Anda memiliki tombol yang menambahkannya dan menekannya dengan cepat). Anda harus menambahkan runnable dengan penundaan.
Alex Burdusel
3

Untuk mendapatkan Tampilan dari posisi tertentu dari recyclerView, Anda perlu memanggil findViewHolderForAdapterPosition (posisi) pada objek recyclerView yang akan mengembalikan RecyclerView.ViewHolder

dari objek RecyclerView.ViewHolder yang dikembalikan dengan itemView Anda dapat mengakses semua Tampilan pada posisi tertentu

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

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

Anda juga dapat melakukan ini, ini akan membantu ketika Anda ingin mengubah tampilan setelah mengklik item posisi recyclerview

@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
sumber
1

Untuk mendapatkan tampilan spesifik dari daftar tampilan pendaur ulang ATAU menunjukkan kesalahan di editeks tampilan pendaur ulang.

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
sumber