Reputation: 11109
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());
}
}
}
Upvotes: 191
Views: 263454
Reputation: 1
*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
Upvotes: 0
Reputation: 11726
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).
Upvotes: 325
Reputation: 835
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();
}
}
});
}
}
Upvotes: 16
Reputation: 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
}
}
});
Upvotes: -1
Reputation: 159
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);
}
});
Upvotes: 0
Reputation: 477
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!...
Upvotes: -1
Reputation: 335
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);
Upvotes: 8
Reputation: 347
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 !");
}
Upvotes: 2
Reputation: 2835
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
Upvotes: 12
Reputation: 5421
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);
}
});
Upvotes: 6
Reputation: 910
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.
Upvotes: 9
Reputation: 802
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);
Upvotes: 6
Reputation: 407
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");
}
Upvotes: 1
Reputation: 1871
If you want the View
, make sure to access the itemView
property of the ViewHolder like so: myRecyclerView.findViewHolderForAdapterPosition(pos).itemView;
Upvotes: 36
Reputation: 11817
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.)
Upvotes: 182