1

I'm using a RecyclerView that displays pages from a book. I have an EditText box that takes you to a page in the book. The only problem is that when it scrolls to the page of the book sometimes it will scroll to the top of the page and sometimes to the bottom. I think this has something to do with the RecyclerView and it not loading the view for the page before i scroll to it. I want it to always scroll to the top of a page but I'm not sure of the best way to go about it.

Here is the relevant code

MainActivity.java

public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText editText = (EditText) findViewById(R.id.page); editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { boolean handled = false; if (actionId == EditorInfo.IME_ACTION_GO) { int p = Integer.valueOf(v.getText().toString()) - 1; scrollToPage(p); handled = true; } return handled; } }); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); // use a linear layout manager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); // specify an adapter (see also next example) mAdapter = new MyAdapter(pages); mRecyclerView.setAdapter(mAdapter); } //*******************RECYCLERVIE***************************************8// public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{ private String[] mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView mTextView; public TextView pageNumber; public ViewHolder(View v) { super(v); mTextView = (TextView) v.findViewById(R.id.info_text); pageNumber = (TextView) v.findViewById(R.id.page_number); } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset) { //my Dataset is an array with 4 members making up the 4 pages// mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.cards, parent, false); // set the view's size, margins, paddings and layout parameters ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]); int page = position + 1; holder.pageNumber.setText("" + page); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } } //******SCROLL TO TOP BUTTON************// public void scrollToTop(View v){ mLayoutManager.scrollToPosition(0); } //*******************SCROLL TO SELECTED PAGE***********// public void scrollToPage(int p){ mLayoutManager.scrollToPosition(p); } } 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- A RecyclerView with some commonly used attributes --> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_alignParentBottom="true"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="GO TO TOP" android:onClick="scrollToTop" android:layout_gravity="bottom|left"/> <EditText android:id="@+id/page" android:layout_width="50dp" android:layout_height="20dp" android:layout_gravity="bottom|center_horizontal" android:imeOptions="actionGo" android:inputType="number" android:background="@color/cardview_light_background"/> </LinearLayout> </RelativeLayout> 

cards.xml

<?xml version="1.0" encoding="utf-8"?> <!-- A CardView that contains a TextView --> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/card_view" android:layout_width="300dp" android:layout_height="500dp" android:layout_gravity="center" card_view:cardCornerRadius="4dp"> <TextView android:id="@+id/info_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/frayedpaper" android:text="@string/body" /> <TextView android:id="@+id/page_number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:text="page"/> </android.support.v7.widget.CardView> 
2
  • 1
    If you replace mLayoutManager.scrollToPosition(p) with mLayoutManager.scrollToPositionWithOffset(p, 1), does it work for you? I had a similar issue and the one pixel offset seemed to magically fix it for me. Commented Nov 14, 2017 at 0:22
  • This did work! Thanks! Commented Nov 14, 2017 at 5:09

1 Answer 1

2

I've run into this problem myself before, and I found that calling LayoutManager.scrollToPositionWithOffset(position, 1) instead of simply LayoutManager.scrollToPosition(position) solved it for me.

Unfortunately, I don't really know why this works. It seems that the one-pixel offset changes the layout manager's calculations somehow; calling scrollToPositionWithOffset(position, 0) didn't work for me. Fortunately, over-scrolling by one pixel wasn't noticeable in my app.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.