当屏幕方向改变时,保存滚动视图的位置

21

这是我的布局:

详细布局

当屏幕方向改变时,我需要保存滚动位置。例如,如果在竖屏模式下屏幕显示从中间名称开始的布局,则在横屏模式下也应该从同一位置开始。

7个回答

67

只需在您的滚动元素上设置android:id。您的视图将自动保存其滚动位置。

来自View.java的代码:15554

protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
        mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
        Parcelable state = onSaveInstanceState();
        if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
            throw new IllegalStateException(
                    "Derived class did not call super.onSaveInstanceState()");
        }
        if (state != null) {
            // Log.i("View", "Freezing #" + Integer.toHexString(mID)
            // + ": " + state);
            container.put(mID, state);
        }
    }
}

2
很棒的答案!我认为这是ScrollView无法恢复其位置的最常见原因。 - athor
7
这应该标记为正确答案。虽然在此情境中张贴View.java的代码有点令人困惑。 - Greg Ennis
2
当我在NestedScrollView中使用RecyclerView时,这并没有对我起作用,但是下面Umesh Clauhan的解决方案有效。 - Minas Mina
哇!令人惊叹的解决方案,而且只有在恢复视图状态时才有效。但是当视图必须重新创建并显示给用户时,这绝对不是一个解决方案。 - sud007

45

当手机方向改变时,保存和恢复ScrollView的滚动位置可以按照以下步骤进行: 在onSaveInstanceState方法中保存当前位置:

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putIntArray("ARTICLE_SCROLL_POSITION",
            new int[]{ mScrollView.getScrollX(), mScrollView.getScrollY()});
}

然后在onRestoreInstanceState方法中恢复位置。需要注意的是,我们需要向ScrollView发布一个Runnable才能使其正常工作:

然后在onRestoreInstanceState方法中恢复位置。需要注意的是,我们需要向ScrollView发送一个Runnable以使其正常工作:

protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    final int[] position = savedInstanceState.getIntArray("ARTICLE_SCROLL_POSITION");
    if(position != null)
        mScrollView.post(new Runnable() {
            public void run() {
                mScrollView.scrollTo(position[0], position[1]);
            }
        });
}

在谷歌上找到了这个解决方案。鸣谢原作者。:)


1
你救了我的一天! - Joaquin Iurchuk
18
没必要这样操作,你只需要在 ScrollView 上设置一个ID即可(详见真正的答案…)。 - Greg Ennis
尝试添加此偏移量以在从垂直方向更改为水平方向时获得精确位置:mScrollView.scrollTo(position[0], position[1] + getScreenWidth()/4); - the_prole

0
在我的三星平板上,我不需要添加太多代码(只需调用超类)。此外,我已经在ListView上有一个名称。
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
}

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/search_text"
        android:maxLines="1"
        android:inputType="text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Enter search string here" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doSearch"
        android:clickable="true"
        android:text="Search"
        android:layout_toRightOf="@id/search_text"/>

    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/list_of_books"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/search_text"
        android:divider="@null"
        android:orientation="vertical" />

</RelativeLayout>

0
Android操作系统在配置更改或由于内存不足而杀死活动时,会保留UI状态。这包括但不限于RecyclerView滚动位置和EditText中的字符串。
然而,您必须设置唯一的id android:id,以便让Android操作系统处理此事。

-1

请勿发布仅包含链接的答案。链接中的内容可能会更改或链接可能停止工作。相反,请在您的答案中包含相关内容,并提供用于归属或进一步阅读的链接。 - TheIT

-5

在清单文件中执行此操作...

  <activity
        android:name=".YourActivity"
        android:configChanges="keyboardHidden|orientation|screenSize"
        android:label="@string/app_name" >
  </activity>

-15
如果您的活动在旋转时不会更改任何内容,可以在清单文件中使用android:configChanges="orientation|keyboardHidden|screenSize"来处理此特定活动。但这显然是一种变通方法,而不是一个正确的解决方案。
注意:
如果您需要为横向和纵向使用不同的视图,或者如果您需要为不同的设备使用不同的视图,则应该使用bundle并在onsaveinstancestate中保存数据,并在oncreate中检索数据。这种方法停止重新创建活动,并且活动假定用户自己处理事情。

1
如果您的横向和纵向视图不同,则这不是一个好的解决方案,因为Activity或Fragment都不会使用此配置重新创建其视图。您可能还会得到一个外观奇怪的操作栏。 - Johan
是的,约翰,同意并相应地修改了答案。 - MrDumb
1
你不应该依赖于配置更改。参考:https://dev59.com/z2sz5IYBdhLWcg3wj4gc#7990543 - Sree
哇,我从未见过任何一个被标记的答案获得这么多的反对票。 - Damn Vegetables
显然不是最好的方式。 - raphaelbgr
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接