I want to auto scroll a list item to top (firstVisible item) in my recycler view and get the view at that position, so I can highlight it, from my fragment.
So, this is the gist of my fragment code :
private void activateNewListItem(int position) {
mLayoutManager().scrollToPositionWithOffset(position, 0);
RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForLayoutPosition(position);
View view = viewHolder.getItemView();
view.setBackgroundColor(getResources().getColor(R.color.esr_light_grey));
}
If position
is 1,2,3,4 etc, mRecyclerView.findViewHolderForPosition(position)
returns a valid ViewHolder,
because I guess RecyclerView has drawn ViewHolders for those indexes in dataSet.
However, if I pass in position
as say, 25, mRecyclerView.findViewHolderForPosition(position)
returns null, because I assume, it hasn't been drawn yet, even thoughI called mLayoutManager.scrollToPositionWithOffset(position, 0)
above it.
What can I do to achieve these two things?
Scroll the list item of dataSet index position
to firstVisibleItem.
Get the View or ViewHolder object of that listItem, so I can change the background or whatever.
Instead of accessing ViewHolder somewhere else, go for a custom selector background in your adapters item layout xml file instead, track the position in your adapter as selected position and call notifydatasetchanged()/notifyItemRangeChanged() to highlight it once the scroll is complete. You already have the scrollToPosition() method, have a scroll listener to track the scroll state.
Example for selector background : item_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android=
"http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:drawable="@color/primary_dark" />
<item android:drawable="@android:color/transparent" />
</selector>
Set it as background to your item xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_list_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/item_selector">
<--- Your layout items here --->
</RelativeLayout>
Your adapter code :
public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> {
private final String[] list;
private int lastCheckedPosition = -1;
public SampleAdapter(String[] list) {
this.list = list;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.sample_layout, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.choiceName.setText(list[position]);
holder.containerView.setSelected(position == lastCheckedPosition);
}
@Override
public int getItemCount() {
return list.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.choice_name)
TextView choiceName;
@Bind(R.id. container_list_item)
View containerView;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lastCheckedPosition = getAdapterPosition();
notifyItemRangeChanged(0, list.length);
}
});
}
}
}
To scroll to any position :
recyclerview.scrollToPosition(position)
Let me know if this helps.
It takes some seconds to update the ViewHolder Information. Just scroll and delay the mRecyclerView.findViewHolderForLayoutPosition
call for some milliseconds (100ms sounds reasonable)
Put this code in your fragment where you are going to scroll to the first RecyclerView item:
RecyclerView.ViewHolder holder = mRecyclerView
.findViewHolderForAdapterPosition(0);
while (holder == null) {
int firstVisiblePosition = mLayoutManager()
.findFirstCompletelyVisibleItemPosition();
RecyclerView.ViewHolder firstVisibleHolder = mRecyclerView
.findViewHolderForAdapterPosition(firstVisiblePosition);
View v = firstVisibleHolder.getItemView();
if (v != null) mRecyclerView.scrollBy(0, (int) v.getY());
else break;
holder = mRecyclerView.findViewHolderForAdapterPosition(0);
}
View view = null;
if (holder != null) view = holder.getItemView();
if (view != null) mRecyclerView.scrollBy(0, (int) view.getY());