确定片段重启是由于屏幕旋转还是 Viewpager 滑动?

Determine if fragment restart is due to screen rotation or Viewpager swipe?

我有一个 ActivityViewPagerViewPager 有很多页,就像一本书。每个片段都有 RecyclerViews 内容很多。以下是我的用例

1 - 当我滑动页面时,RecyclerView 必须从列表的开头开始。 2. 如果我旋转我的设备,它应该从我旋转前离开的最后位置精确读取。

如果我不使用任何逻辑,第二个场景就可以完美运行。即旋转。但不是第一种情况。

如果我像下面那样做一些逻辑。有助于实现第一种情况,但不是第二种情况。

  @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    if (savedInstanceState==null) {
        mIsFirstTime = true;
    }
}

@Override
public void onResume() {
    super.onResume();
    try {
        getActivity().invalidateOptionsMenu();
            if (!mIsFirstTime) {
                mListView.scrollToPosition(0);                
            }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

所以我的问题是

How can I determine a fragment restart is due to screen rotation or Viewpager swipe?

我已经试过了 onConfigurationChanged(Configuration newConfig) 。但这对我没有帮助。你能帮帮我吗

我认为您可以声明一个变量并在滑动操作时检查状态是否为真。

viewPager.addOnPageChangeListener(new OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

public void onPageSelected(int position) {
// here assign the variable to true;
// This method will get called only after a swipe action is invoked on 
//viewpager.  
 }});

在您的片段中检查变量 status 是否为真,如果不是从方向生成的,则将 变量重置为假.

编码愉快:)

在您的 Fragment 和 View Pager 中使用 onSaveInstanceState() 函数并使用保存的实例滚动到旧位置。

In cases where the UI data to preserve is simple and lightweight, you might use onSaveInstanceState() alone to preserve your state data. In cases where you have complex data that you want to preserve, you can use a combination of ViewModel objects, the onSaveInstanceState() method, and persistent local storage.

参考 Saving UI States

使用示例 onSaveInstanceState()

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    if (savedInstanceState==null) {
            if(savedInstanceState.containsKey("position")){
                int positon = savedInstanceState.getInt("position",0);
                YOUR_RECYCLER_VIEW.scrollToPosition(positon);
        }
    }
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("position",YOUR_RECYLER_VIEW.getVerticalScrollbarPosition());
}

在此处了解更多信息

  1. How to use onSaveInstanceState() and onRestoreInstanceState()?

  2. Android Developers Official Documention

了解viewpage使用的pageChange

myViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        //Use your logic here.

        }

        @Override
        public void onPageSelected(int position) {

        //Use your logic here.

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        //Use your logic here.

        }
    });

来自

My question is how I know that onSaveInstanceState() is called due to screen orientation change and not fragment restart

您可以通过 Activity#isChangingConfigurations() API.


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        if (isChangingConfigurations()) {
            // this callback is executed as a result of a configuration change (e.g. orientation change)
        } else {
            // no configuration change happens (e.g. a click on a home button would end up here)
        }
    }

现在您可以将布尔值保存到 Bundle outState 并在重新创建后进行适当的设置 UI:


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("isConfigurationChange", isChangingConfigurations());
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // initialization logics here

        if (savedInstanceState != null) {
            boolean isConfigurationChange = savedInstanceState.getBoolean("isConfigurationChange");

            // if `onCreate` is called as a result of configuration change
            if (isConfigurationChange) {
                // view hierarchy is not yet laid out, have to post an action 
                listView.post(new Runnable() {
                    @Override
                    public void run() {
                        // we are guaranteed, that `listView` is already laid out
                        listView.scrollToPosition(0);
                    }
                });
            }
        }
    }

请注意,在 onResume() 中执行布尔值检查逻辑是一个错误(按下主页按钮并导航回应用程序会导致再次滚动到顶部,这是不需要的)。相反,应该选择 onCreate() 作为正确的回调。

为什么滚动到零位置? mListView.scrollToPosition(0);

我认为您可以在片段的 onPause 中保存 RecyclerView 的当前位置,然后在重新创建后 - 转到该位置。