191

I have an activity with a RecyclerView and an ImageView. I am using the RecyclerView to show a list of images horizontally. When I click on an image in the RecyclerView the ImageView in the activity should show a bigger picture of the image. So far everything works fine.

Now there are two more ImageButtons in the activity: imageButton_left and imageButton_right. When I click on imageButton_left, the image in the ImageView should turn left and also, the thumbnail in the RecyclerView should reflect this change. Similar is the case with imageButton_right.

I am able to rotate the ImageView. But, how can I rotate the thumbnail in the RecyclerView? How can I get the ViewHolder's ImageView?

Code:

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

My Activity Code:

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

My Custom Adapter for 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()); } } } 
4
  • 1
    You should make it in your viewHolder constructor, add a property that will tell you if the image needs to be rotated, then just change that property on your data and call notifyDataSetChanged to make the recyclerView reload Commented Nov 18, 2015 at 15:47
  • Do any of the answers solve your problem? Commented Sep 8, 2016 at 16:44
  • ViewHolder should be static for performance issue. All variables from the outer class should be passed through the constructor. Commented Mar 13, 2017 at 21:19
  • 1
    As a supplement to @Scott's answer Click here Commented Mar 2, 2018 at 0:57

16 Answers 16

325

This is what you're looking for.

I had this problem too. And like you, the answer is very hard to find. But there IS an easy way to get the ViewHolder from a specific position (something you'll probably do a lot in the Adapter).

myRecyclerView.findViewHolderForAdapterPosition(pos);

NOTE: If the View has been recycled, this will return null. Thanks to Michael for quickly catching this omission. Furthermore, if the user is scrolling quickly, the view can be recycled even after you obtain this ViewHolder, causing all kinds of problems. So be careful when using this technique, especially if you're doing relatively slow work like changing the look of the View(s).

Sign up to request clarification or add additional context in comments.

11 Comments

This works, however, if the ViewHolder you are trying to reference was "recycled", it will return null.
@Michael, good catch! That's a warning to all you out there, test for null first (yeah, like everything else in Android)!
Can we do this from inside the adapter?
@Mauker : You can use this from anything that can access the RecyclerView instance.
@ScottBiggs is there any way to access children that are not yet shown or visible ?
|
182

I suppose you are using a LinearLayoutManager to show the list. It has a nice method called findViewByPosition that

Finds the view which represents the given adapter position.

All you need is the adapter position of the item you are interested in.

edit: as noted by Paul Woitaschek in the comments, findViewByPosition is a method of LayoutManager so it would work with all LayoutManagers (i.e. StaggeredGridLayoutManager, etc.)

6 Comments

Thats actually a method of the LayoutManager so this will work for all LayoutManager subclasses.
Looked at the source code. LinearLayoutManger looks up via directAccess on the backing array when not in prelayout, whereas the recyclerView method always does traversal. So this method is likely more efficient.
Hey @stanO can you please help me with this stackoverflow.com/questions/49952965/…
Returns: View--The child view that represents the given position or null if the position is not laid out... recyclerview --> most things return null
Keep in mind that you have to wait until adapter will added to list, see my answer below for details
|
36

If you want the View, make sure to access the itemView property of the ViewHolder like so: myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;

Comments

16

You can use use both

recyclerViewInstance.findViewHolderForAdapterPosition(adapterPosition) and recyclerViewInstance.findViewHolderForLayoutPosition(layoutPosition). Be sure that RecyclerView view uses two type of positions

Adapter position: Position of an item in the adapter. This is the position from the Adapter's perspective.

Layout position: Position of an item in the latest layout calculation. This is the position from the LayoutManager's perspective. You should use getAdapterPosition() for findViewHolderForAdapterPosition(adapterPosition) and getLayoutPosition() for findViewHolderForLayoutPosition(layoutPosition).

Take a member variable to hold previously selected item position in recyclerview adapter and other member variable to check whether user is clicking for first time or not.

Sample code and screen shots are attached for more information at the bottom.

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

} first element selected second element selected and previously selected item becomes unselected fifth element selected and previously selected item becomes unselected

2 Comments

And I thought this discussion was exhausted! Thanks for further clarifying this issue.
Here I am getting the NullPointer exception in the else block when I am trying to change the color of the previous item, so I added the null check, now it is never entering into that block if it is having NullPointer exception, so previous item color is never changed. now my Recycler view has items with multiple colored items. how do i solve this
12

You can simply use "findViewHolderForAdapterPosition" method of recycler view and you will get a viewHolder object from that then typecast that viewholder into your adapter viewholder so you can directly access your viewholder's views

following is the sample code for kotlin

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

Comments

9

You can make ArrayList of ViewHolder :

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

and, all store ViewHolder(s) in the list like :

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

and add/remove other ViewHolder in the ArrayList as per your requirement.

1 Comment

Thank you I for been struggling to get recycled holders for like 2 days.
8

To get a View from a specific position of recyclerView you need to call findViewHolderForAdapterPosition(position) on recyclerView object that will return RecyclerView.ViewHolder

from the returned RecyclerView.ViewHolder object with itemView you can access all Views at that particular position

RecyclerView.ViewHolder rv_view = recyclerView.findViewHolderForAdapterPosition(position); ImageView iv_wish = rv_view.itemView.findViewById(R.id.iv_item); 

Comments

6

You can get a view for a particular position on a recyclerview using the following

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

1 Comment

If I do this, then this error comes {itemView' on a null object reference}. What should I do ?
6

Keep in mind that you have to wait until adapter will added to list, then you can try to getting view by position

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

1 Comment

This is not always working if you add multiple items (i.e.: if you have a button that adds them and press it fast). You should add the runnable with delay.
2

To get specific view from recycler view list OR show error at edittext of recycler view.

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

Comments

1

You can as well do this, this will help when you want to modify a view after clicking a recyclerview position item

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

Comments

0

You can use below

mRecyclerview.getChildAt(pos); 

1 Comment

It's not true. This way you will get a child view to RecyclerView, not it's item (0th, 1st, 2nd, etc).
0

RecyclerView - Get view at particular position. //int is = position; This line of code worked for me.

 @Override public void onBindViewHolder(@NonNull @org.jetbrains.annotations.NotNull QuizAdapter.MyViewHolder holder, int position) { final QuizModel tmodel = modellist.get(position); holder.tv_question.setText(tmodel.getQuestion()); holder.tv_option_One.setText(tmodel.getOptionA()); holder.tv_option_two.setText(tmodel.getOptionB()); holder.tv_option_three.setText(tmodel.getOptionC()); holder.tv_option_four.setText(tmodel.getOptionD()); holder.tv_option_five.setText(tmodel.getOptionE()); holder.ll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int is = position; Toast.makeText(v.getContext(), "count" + is, Toast.LENGTH_LONG).show(); Intent i = new Intent(context, DetailsQuizActivity.class); i.putExtra("question", tmodel.getQuestion()); i.putExtra("option_a", tmodel.getOptionA()); i.putExtra("option_b", tmodel.getOptionB()); i.putExtra("option_c", tmodel.getOptionC()); i.putExtra("option_d", tmodel.getOptionD()); i.putExtra("option_e", tmodel.getOptionE()); i.putExtra("answer", tmodel.getOptionAnswer()); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } }); 

Comments

0

*If the adapter remains of equal size, (not changed by added item or remove), you can create a list of ViewHolder in adapter, then in onCreateViewHolder you add the new ViewHolder to the list. Where you can access adapter you can access to ViewHolder to the particular position with the list: adapter.listHolder.get(position)

*For adpater not equaled size: little bite complex, update listHolder in fonction of new item added to holder, or removed

2 Comments

Lists can be unpredictably long. Suggesting to save all the views in a list can lead to memory issues.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
-1

If you guys are having null with every attempt to get a view with any int position, try to add a new constructor parameter to your adapter like this for example:

class RecyclerViewTableroAdapter( private val fichas: Array<MFicha?>, private val activity: View.OnClickListener, private val indicesGanadores:MutableList<Int> ) : RecyclerView.Adapter<RecyclerViewTableroAdapter.ViewHolder>() { //CODE } 

I added indicesGanadores to color my cardview background if my game is won.

override fun onBindViewHolder(holder: ViewHolder, position: Int) { //CODE if(indicesGanadores.contains(position)){ holder.cardViewFicha.setCardBackgroundColor((activity as MainActivity).resources.getColor(R.color.DarkGreen)) } //MORE CODE } 

If I don't have to color my background yet I just send an empty mutable list like this:

binding.recyclerViewMain.adapter = RecyclerViewTableroAdapter(fichasTablero, this@MainActivity, mutableListOf<Int>()) 

Happy coding!...

Comments

-1
recyclerView.post(new Runnable() { @Override public void run() { for (int i = 0; i < 5; i++) { View viewTemp = recyclerView.getLayoutManager().findViewByPosition(i); CardView cardView = (CardView) viewTemp.findViewById(R.id.cardView); //TO DO } } 

});

1 Comment

Hello @peter-linh, thank you for contributing to Stackoverflow, Please make your answers elaborate. Take a look at stackoverflow.com/help/how-to-answer to see how to write a good answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.