Maintain WebView content scroll position on orientation change

前端 未结 8 769
隐瞒了意图╮
隐瞒了意图╮ 2020-12-23 02:04

The browsers in Android 2.3+ do a good job at maintaining the scrolled position of content on an orientation changed.

I\'m trying to achieve the same thing for a We

8条回答
  •  抹茶落季
    2020-12-23 02:26

    To restore the current position of a WebView during orientation change I'm afraid you will have to do it manually.

    I used this method:

    1. Calculate actual percent of scroll in the WebView
    2. Save it in the onRetainNonConfigurationInstance
    3. Restore the position of the WebView when it's recreated

    Because the width and height of the WebView is not the same in portrait and landscape mode, I use a percent to represent the user scroll position.

    Step by step:

    1) Calculate actual percent of scroll in the WebView

    // Calculate the % of scroll progress in the actual web page content
    private float calculateProgression(WebView content) {
        float positionTopView = content.getTop();
        float contentHeight = content.getContentHeight();
        float currentScrollPosition = content.getScrollY();
        float percentWebview = (currentScrollPosition - positionTopView) / contentHeight;
        return percentWebview;
    }
    

    2) Save it in the onRetainNonConfigurationInstance

    Save the progress just before the orientation change

    @Override
    public Object onRetainNonConfigurationInstance() {
        OrientationChangeData objectToSave = new OrientationChangeData();
        objectToSave.mProgress = calculateProgression(mWebView);
        return objectToSave;
    }
    
    // Container class used to save data during the orientation change
    private final static class OrientationChangeData {
        public float mProgress;
    }
    

    3) Restore the position of the WebView when it's recreated

    Get the progress from the orientation change data

    private boolean mHasToRestoreState = false;
    private float mProgressToRestore;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.main);
    
        mWebView = (WebView) findViewById(R.id.WebView);
        mWebView.setWebViewClient(new MyWebViewClient());
        mWebView.loadUrl("http://stackoverflow.com/");
    
        OrientationChangeData data = (OrientationChangeData) getLastNonConfigurationInstance();
        if (data != null) {
            mHasToRestoreState = true;
            mProgressToRestore = data.mProgress;
        }
    }
    

    To restore the current position you will have to wait the page to be reloaded ( this method can be problematic if your page takes a long time to load)

    private class MyWebViewClient extends WebViewClient {
        @Override
        public void onPageFinished(WebView view, String url) {
            if (mHasToRestoreState) {
                mHasToRestoreState = false;
                view.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        float webviewsize = mWebView.getContentHeight() - mWebView.getTop();
                        float positionInWV = webviewsize * mProgressToRestore;
                        int positionY = Math.round(mWebView.getTop() + positionInWV);
                        mWebView.scrollTo(0, positionY);
                    }
                // Delay the scrollTo to make it work
                }, 300);
            }
            super.onPageFinished(view, url);
        }
    }
    

    During my test I encounter that you need to wait a little after the onPageFinished method is called to make the scroll working. 300ms should be ok. This delay make the display to flick (first display at scroll 0 then go to the correct position).

    Maybe there is an other better way to do it but I'm not aware of.

提交回复
热议问题