Reputation: 89
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>
Upvotes: 1
Views: 1555
Reputation: 54194
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.
Upvotes: 2