Manage scroll position in scrollview during orient

2019-06-03 23:22发布

问题:

I have a Bookshelf which is implemented as follows:

I have a ScrollView which contains a nested TableLayout which acts as a container for dynamically generated TableRows.

   <com.test.bookshelf.CustomScrollView
        android:id="@+id/scrollview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/newHeader"
        android:overScrollMode="never"
        android:fadingEdge="none" >

        <TableLayout
            android:id="@+id/tblLayout"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="0dp" >
        </TableLayout>
    </com.test.bookshelf.CustomScrollView>

Custom ScrollView code:

public class CustomScrollView extends ScrollView {

    private boolean enableScrolling = true;
    private ScrollViewListener scrollViewListener = null;

    public interface OnEndScrollListener {
        public void onEndScroll();
    }

    private OnEndScrollListener mOnEndScrollListener;

    public boolean isEnableScrolling() {
        return enableScrolling;
    }

    public void setEnableScrolling(boolean enableScrolling) {
        this.enableScrolling = enableScrolling;
    }

    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomScrollView(Context context) {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        if (isEnableScrolling()) {
            return super.onInterceptTouchEvent(ev);
        } else {
            return false;
        }
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if(scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }

    public OnEndScrollListener getOnEndScrollListener() {
        return mOnEndScrollListener;
    }

    public void setOnEndScrollListener(OnEndScrollListener mOnEndScrollListener) {
        this.mOnEndScrollListener = mOnEndScrollListener;
    }
}

Each table row consist of a fixed number of columns which is dynamically calculated based on the total number of books. On orientation change this entire layout is re created.

When the bookshelf is being generated I'm storing the total number of rows in a static variable.

When the user clicks on any of book it takes them to the details page. I am storing the current scroll position during the click event:

public static currentScrollPosition = 0;

imageviewobj.setOnClickListener(new View.OnClickListener() 
{
   @Override
   public void onClick(View v) 
   {
      currentScrollPosition = scrollviewObj.getScrollY();

....

When the user returns to this screen I restore the scroll position by using this value.

scrollviewObj.post(new Runnable() {
        @Override
        public void run() {
            scrollviewObj.scrollTo(0, currentScrollPosition);
        } 
    });

But how do I calculate the equivalent scroll position during orientation change? The vertical offset (scroll position) of a Book in the portrait mode is different from landscape mode because the number of rows and columns differ.

Any thoughts on this?

回答1:

You should simply keep the index of the row that is being seen (or clicked) in your case, and persist this information thanks to onSaveInstanceState/onCreate.

After that when the rotation will occur, inside your new instance onCreate, compute the vertical offset at which you will have to scroll.

For this, you will need to add a global tree layout observer to your list cells to get their height, if it is not fixed. And then you can ask to scroll.

This method allows you to be independent of your view by keeping track of the index in the list. It will then work in portrait to landscape but also landscape to portrait.