Finding top offset of first visible item in a RecyclerView

tylerjroach picture tylerjroach · Dec 1, 2015 · Viewed 18.6k times · Source

I have a RecyclerView + LinearLayoutManger which is using an adapter that holds chat messages. I limit the number of chat messages to the most 100 recent. This issue is that when I remove the older chats, the scroll position of the chats in the recyclerview changes because index 0 was removed. I began writing the code below:

int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
View v = layoutManager.getChildAt(firstVisiblePosition);
if (firstVisiblePosition > 0 && v != null) {
    int offsetTop = //need to get the view offset here;
    chatAdapter.notifyDataSetChanged();

    if (firstVisiblePosition - 1 >= 0 && chatAdapter.getItemCount() > 0) {
        layoutManager.scrollToPositionWithOffset(firstVisiblePosition - 1, offsetTop);
    }
}

I thought it would be easy to get the visible offset of the first visible item position. Ex. if the first visible view is 300dp but only the last 200dp is visible, I would like to get the 100 offset.

This way I could use scrollToPositionWithOffset(firstVisiblePosition - 1, offsetTop).

Am I missing something here? This seems like it would be an easy problem to figure out, but I haven't seen any methods that would support this.

Answer

tylerjroach picture tylerjroach · Dec 1, 2015

@Blackbelt. Thank you for getting me on the right track.

The offset that I needed was actually just v.getTop();

My real problem was in getChildAt(). Apparently getChildAt begins at the first visible position, not at the position of the adapter. The documentation is poorly written in this case.

Here is the resulting code.

int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
View v = layoutManager.getChildAt(0);
if (firstVisiblePosition > 0 && v != null) {
    int offsetTop = v.getTop();
    chatAdapter.notifyDataSetChanged();

    if (firstVisiblePosition - 1 >= 0 && chatAdapter.getItemCount() > 0) {
         layoutManager.scrollToPositionWithOffset(firstVisiblePosition - 1, offsetTop);
    }
}