How to Get the Position Selected in a Recyclerview

How do I get the position selected in a RecyclerView?

Set your onClickListeners 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 to Activity/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 and ViewHolder:

      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



Leave a reply



Submit