android-fragmentsandroid-recyclerviewandroid-viewholderandroid-scrolllinearlayoutmanager

RecyclerView scroll to position and get that view


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?

  1. Scroll the list item of dataSet index position to firstVisibleItem.

  2. Get the View or ViewHolder object of that listItem, so I can change the background or whatever.


Solution

  • 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.