How do I get the position selected in a RecyclerView?
Set your onClickListener
s on onBindViewHolder()
and you can access the position from there. If you set them in your ViewHolder
you won't know what position was clicked unless you also pass the position into the ViewHolder
EDIT
As pskink
pointed out ViewHolder
has a getPosition()
so the way you were originally doing it was correct.
When the view is clicked you can use getPosition()
in your ViewHolder
and it returns the position
Update
getPosition()
is now deprecated and replaced with getAdapterPosition()
Update 2020
getAdapterPosition()
is now deprecated and replaced with getAbsoluteAdapterPosition()
or getBindingAdapterPosition()
Kotlin code:
override fun onBindViewHolder(holder: MyHolder, position: Int) {
// - get element from your dataset at this position
val item = myDataset.get(holder.absoluteAdapterPosition)
}
How to get currently selected item position in RecyclerView?
I'm Java Developer so I cannot code with Kotlin but I'll show you how to get any view's position in RecyclerView
holder.itemView.setOnClickListener(view -> {
Toast.makeText(context, "This is position of your Every ItemViews", Toast.LENGTH_SHORT).show();
});
In your onBindViewHolder
use this code holder.itemView.setOnClickListener
and create new click listener. Here you can get the position of your items by coding and you can check by adding Toast
.
your code lookalike below:-
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = list[position]
holder.itemView.findViewById<TextView>(R.id.task).text = item.task
holder.itemView.findViewById<TextView>(R.id.taskDescription).text = item.task_Details
holder.itemView.setOnClickListener(view -> {
Toast.makeText(context, "This is position of your Every ItemViews", Toast.LENGTH_SHORT).show();
});
}
Make sure to change JAVA to Kotlin of my code. If you any problem is causing, Let me know
Get selected item position of RecyclerView
You can use the ViewHolder's getAdapterPosition()
to retrieve the item's position within an interface method. Then store the clicked position in a member variable.
Additionally, there shouldn't be a need to call position++
from within your onBindViewHolder
.
// Create a member variable to store the clicked position
public int clickedPos = -1;
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// ...
holder.addIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// When you're inside the click listener interface,
// you can access the position using the ViewHolder.
// We'll store the position in the member variable in this case.
clickedPos = holder.getAdapterPosition();
}
});
// Remove the 'position++' call as the position should already be handled without explicitly updating it.
}
@Override
public boolean onMenuItemClick(MenuItem item) {
// You can use clickedPos here to perform whatever tasks you need.
// ...
}
RecyclerView - Get the selected position and pass the position to another activity where the same list will appear with that specific item selected
There was a lot of changes in the question and hence the last update of this answer below is the final version.
As far as I could understand about the problem, I can see you are very close to the solution if I had understood correctly. The SearchEngineAdapter
already has a selectedItem
variable in it which can be used for highlighting the item selected in ActivitySearchEngine
as well. You just have to modify the adapter a little bit like the following. I am rewriting the adapter here.
public class SearchEngineAdapter extends RecyclerView.Adapter<SearchEngineAdapter.ViewHolder> {
private int selectedItem = 0;
private static RecyclerViewClickListener itemListener;
private Context context;
ArrayList<SearchEngine> arrayList = new ArrayList<>();
// Added another argument to be passed in the constructor
public SearchEngineAdapter(Context context, ArrayList<SearchEngine> arrayList, int selectedItem) {
this.context = context;
this.arrayList = arrayList;
this.selectedItem = selectedItem;
}
@NonNull
@Override
public SearchEngineAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.s_engine_item, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int i) {
if (selectedItem == i) {
holder.tvIcon.setBackgroundColor(Color.parseColor("#30000000"));
} else {
holder.tvIcon.setBackgroundColor(Color.parseColor("#00000000"));
}
holder.tvIcon.setImageResource(arrayList.get(i).getIcon());
holder.tvId.setText(arrayList.get(i).getId());
holder.tvSearchUrl.setText(arrayList.get(i).getUrl());
holder.tvIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int PreviousSelectedItem = selectedItem;
selectedItem = i;
holder.tvIcon.setBackgroundColor(Color.parseColor("#30000000"));
notifyItemChanged(PreviousSelectedItem);
notifyDataSetChanged();
}
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView tvId, tvSearchUrl;
ImageView tvIcon;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvId = itemView.findViewById(R.id.ivEngineText);
tvIcon = itemView.findViewById(R.id.ivEngine);
tvSearchUrl = itemView.findViewById(R.id.ivSearchUrl);
}
}
}
Check that, I just have modified the constructor of your adapter, taking another extra variable which is selectedItem
. Just pass the selected item position when you are initializing the adapter in both activities. In the default case, you can pass -1, I think you get the idea.
You have passed the selected item position to the ActivitySearchEngine
as well. Which can be used for initializing for the desired behavior. Hope that helps!
Update 1:
I would like to suggest you put the following code to your onResume
function in the ActivitySearchEngine
class. You might consider removing the lines from the onCreate
function of your code as well.
@Override
public void onResume() {
super.onResume();
Intent receivedIntent = getIntent();
selectedName = receivedIntent.getStringExtra("name");
selectedID = receivedIntent.getIntExtra("id", 1); // NOTE: -1 is just the default value
selectedSearchUrl = receivedIntent.getStringExtra("url");
sEngineAdapter = new SearchEngineAdapter(context, arrayList, selectedID);
paramRecyclerView.setAdapter(sEngineAdapter);
}
Update 2:
The RecyclerView
in your MainActivity
is getting reloaded as you are setting the adapter again to the RecyclerView
in the onResume
function. Moreover, you are trying to get data from intent which is not available here I think because you have not set any data to be sent to the MainActivity
when you return back from the ActivitySearchEngine
. Hence, the RecyclerView
is reloading again with a fresh set of data.
You might remove the code associated with your RecyclerView
from the onResume
function of the MainActivity
to remove this complication as I think this is not necessary. So the updated onResume
function will look like the following.
protected void onResume() {
super.onResume();
searchPlugin.setText("");
getChangeColor();
}
Update 3:
Take a public static
variable in your MainAcitivity
and declare it as a global variable like the following.
// Setting 0 as you wanted to put the first item at the first time
// If you do not want that, then initialize with -1
public static int selectedItem = 0;
Now inside your onCreate
function, remove the lines for getting the intent
.
paramRecyclerView = findViewById(R.id.lvEngines);
paramRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
paramRecyclerView.setHasFixedSize(true);
// Remove the following
// Intent intent = getIntent();
// int intValue = intent.getIntExtra("selected", 0);
// Move the adapter setup to the onResume
// sEngineAdapter = new SearchEngineAdapter(context, arrayList, selectedItem);
// paramRecyclerView.setAdapter(sEngineAdapter);
// Calling network APIs to populate the arrayList.
Modify the onResume
function in the MainActivity
to set up the adapter there.
protected void onResume() {
super.onResume();
searchPlugin.setText("");
getChangeColor();
// Set the adapter here
sEngineAdapter = new SearchEngineAdapter(context, arrayList, selectedItem);
paramRecyclerView.setAdapter(sEngineAdapter);
}
Modify the onClickListener
in your adapter like the following. Just add a new line there.
holder.tvIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("search_engines");
intent.putExtra("url", url);
int PreviousSelectedItem = selectedItem;
selectedItem = i;
// Set the static value in the MainActivity
// This can be accessed from all other classes
MainActivity.selectedItem = i;
intent.putExtra("selected", selectedItem);
holder.tvIcon.setBackgroundColor(Color.parseColor("#30000000"));
notifyItemChanged(PreviousSelectedItem);
notifyDataSetChanged();
}
});
Hope that helps!
Get clicked item and its position in RecyclerView
Based on the link: Why doesn't RecyclerView have onItemClickListener()? and How RecyclerView is different from Listview?, and also @Duncan's general idea, I give my solution here:
Define one interface
RecyclerViewClickListener
for a passing message from the adapter toActivity
/Fragment
:public interface RecyclerViewClickListener {
public void recyclerViewListClicked(View v, int position);
}In
Activity
/Fragment
implement the interface, and also pass listener to adapter:@Override
public void recyclerViewListClicked(View v, int position){... ...}
//set up adapter and pass clicked listener this
myAdapter = new MyRecyclerViewAdapter(context, this);In
Adapter
andViewHolder
:public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {
... ...
private Context context;
private static RecyclerViewClickListener itemListener;
public MyRecyclerViewAdapter(Context context, RecyclerViewClickListener itemListener) {
this.context = context;
this.itemListener = itemListener;
... ...
}
//ViewHolder class implement OnClickListener,
//set clicklistener to itemView and,
//send message back to Activity/Fragment
public static class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
... ...
public ItemViewHolder(View convertView) {
super(convertView);
... ...
convertView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
itemListener.recyclerViewListClicked(v, this.getPosition());
}
}
}
After testing, it works fine.
[UPDATE]
Since API 22, RecyclerView.ViewHolder.getPosition()
is deprecated, so instead with getLayoutPosition()
.
RecyclerView - Get position from ViewHolder
You can have to position of your ViewHolder
with:
getAdapterPosition()
How to select only one switch in a recycler view?
Your logic is a bit incorrect.
You do :
if (list.get(position).get(0).equals(selected)) holder.switchButton.setChecked(true);
else holder.switchButton.setChecked(false);
And this invokes the checkedChange listener that you set a line later, in the next iteration after it has been set for the first time.
Remove the checkChangeListener and set a click listener instead.
Also, set the click listener in the onCreateViewHolder
rather than in the onBindViewHolder
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.list_element, parent, false);
ViewHolder vh = new ViewHolder(view);
vh.switchButton.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View view) {
setItemSelected(vh.getAdapterPosition());
}
});
return vh;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position)
{
boolean isSelected = list.get(position).get(0).equals(selected);
holder.switchButton.setChecked(isSelected);
}
private void setItemSelected(int position) {
DA.select(list.get(position).get(0));
selected = list.get(position).get(0);
notifyDataSetChanged();
}
How to tell RecyclerView to start at specific item position
I found a solution myself:
I extended the LayoutManager:
class MyLayoutManager extends LinearLayoutManager {
private int mPendingTargetPos = -1;
private int mPendingPosOffset = -1;
@Override
public void onLayoutChildren(Recycler recycler, State state) {
if (mPendingTargetPos != -1 && state.getItemCount() > 0) {
/*
Data is present now, we can set the real scroll position
*/
scrollToPositionWithOffset(mPendingTargetPos, mPendingPosOffset);
mPendingTargetPos = -1;
mPendingPosOffset = -1;
}
super.onLayoutChildren(recycler, state);
}
@Override
public void onRestoreInstanceState(Parcelable state) {
/*
May be needed depending on your implementation.
Ignore target start position if InstanceState is available (page existed before already, keep position that user scrolled to)
*/
mPendingTargetPos = -1;
mPendingPosOffset = -1;
super.onRestoreInstanceState(state);
}
/**
* Sets a start position that will be used <b>as soon as data is available</b>.
* May be used if your Adapter starts with itemCount=0 (async data loading) but you need to
* set the start position already at this time. As soon as itemCount > 0,
* it will set the scrollPosition, so that given itemPosition is visible.
* @param position
* @param offset
*/
public void setTargetStartPos(int position, int offset) {
mPendingTargetPos = position;
mPendingPosOffset = offset;
}
}
It stores my target position. If onLayoutChildren
is called by RecyclerView, it checks if adapters itemCount is already > 0. If true, it calls scrollToPositionWithOffset()
.
So I can tell immediately what position should be visible, but it will not be told to LayoutManager before position exists in Adapter.
Related Topics
How to Wrap the Height of a Viewpager to the Height of Its Current Fragment
List of Files in Assets Folder and Its Subfolders
Pass Arraylist<? Implements Parcelable> to Activity
Datepicker Shows Wrong Value of Month
Android: Determine Active Input Method from Code
Expand/Collapse Lollipop Toolbar Animation (Telegram App)
Recyclerview Gridlayoutmanager: How to Auto-Detect Span Count
How to Draw Text with a Border on a Mapview in Android
Android Split Action Bar with Action Items on the Top and Bottom
Why Was Actionbaractivity Deprecated
How to Use Android Progressbar in Determinate Mode
Android Place Picker Closes Immediately After Launch
Videoview Getdrawingcache Is Returning Black
How to Automate the Android Sdk Installation
Fragments Destroyed/Recreated with Jetpack's Android Navigation Components