ScrollView .scrollTo无效?如何在旋转屏幕时保存ScrollView位置

45

好的..我一定是忽略了某个非常简单的东西,但我认为我正在尝试做一些相当基本的事情.. 就是在屏幕方向变化时保留ScrollView的滚动条位置...

这是我的onSaveInstanceState和onRestoreInstanceState代码.. sView是ScrollView布局的容器。 在我的ScrollView中有一个带有很多TextView的LinearLayout。

    @Override 
public void onSaveInstanceState(Bundle outState) 
{
    //---save whatever you need to persist—

    outState.putInt("sViewX",sView.getScrollX());
    outState.putInt("sViewY",sView.getScrollY());

super.onSaveInstanceState(outState);

}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) 
{
    super.onRestoreInstanceState(savedInstanceState);

    sViewX = savedInstanceState.getInt("sViewX");   
    sViewY = savedInstanceState.getInt("sViewY");

    sView.scrollTo(sViewX, sViewY);

}
如果我在恢复过程中设置Toast的值为sViewX和sViewY,这些值会被保留并且是正确的。
编辑:我尝试在onCreate中执行sView.scrollTo(0,150);,只是想看看是否会将活动打开到下方150像素,但没有成功。我认为我的问题与.scrollTo方法有关。

1
作为参考,如果您使用片段,则 onRestoreInstanceState 必须放在 onActivityCreated() 方法中。另外,请记得检查:if (savedInstanceState != null)。 - Martin Marconcini
7个回答

130

我想通了。

由于我在onCreate中使用setText设置TextView,调用.scrollTo不起作用。

所以现在我使用以下内容:

sView.post(new Runnable() {
    @Override
    public void run() {
        sView.scrollTo(sViewX, sViewY);
    } 
});

当我没有使用线程时,它不会产生任何效果,为什么呢? - Kushal Shah
这其实很有道理,但是当我尝试将其应用到一个webview上时,它不起作用。 - TacB0sS
11
对于仍然不明白为什么这个方法可行的人来说,原因是ScrollView在添加到布局中之前无法滚动。当ScrollView被添加到视图中时,post(Runnable)方法会被调用,从而使你可以滚动。类似的问题也出现在View.getWidth()返回0的情况下,如此处所讨论的。 - Sourabh
1
这对我也没有用。原因是它取决于你何时将项添加到滚动视图中,因为这会确定其大小。如果您使用 y > 最大高度 调用 scrollTo(x,y),则滚动视图将滚动到当前 ScrollView 的末尾。如果稍后添加更多项,则不再处于 ScrollView 的末尾。我在添加完视图到 ScrollView 后立即调用此函数。 - amitfr

2
在组件未创建之前,请勿启动滚动,因为在组件未创建之前,滚动不起作用:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    scrollView.scrollTo(.... 

所有其他的解决方案对我都不起作用。只有在 Android 的 OnWindowFocusChanged 方法中才能绘制视图,以前不知道!谢谢! - Gustavo Baiocchi Costa

1

这对我很有效

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putInt(SystemGlobal.SCROLL_Y, mRelativeLayoutMain.getTop());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onRestoreInstanceState(savedInstanceState);
    mRelativeLayoutMain.scrollTo(0, savedInstanceState.getInt(SystemGlobal.SCROLL_Y));
}

1

onRestoreInstanceState()太早了,无法滚动视图。 这就是为什么发布新的Runnable有帮助,但不总是有效。有时甚至需要使用postDelayed()才能让它工作。 对于Fragment,可以改用onViewCreated():

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    sViewX = savedInstanceState.getInt("sViewX");   
    sViewY = savedInstanceState.getInt("sViewY");
    sView.scrollTo(sViewX, sViewY);
}

1
这段代码对我来说可以实现动态滚动选项卡,也许对你有用。
TabHost tabHost;
int currentActiveTab;
HorizontalScrollView tabsHorizontalScrollView;
//some code ...
tabHost = getTabHost();
tabsHorizontalScrollView = findViewById(R.id.tabsHorizontalScrollView);
currentActiveTab = 8;
//some code ...
tabHost.setCurrentTab(currentActiveTab);
tabHost.getTabWidget().getChildAt(currentActiveTab).post(new Runnable() {
  @Override
  public void run() {
    tabsHorizontalScrollView.scrollTo(tabHost.getTabWidget().getChildAt(currentActiveTab).getLeft(), tabsHorizontalScrollView.getScrollY());
  }
});

0

针对MVVMCross:

protected override void OnSaveInstanceState(Bundle outState)
{
    base.OnSaveInstanceState(outState);

    ScrollView sv = FindViewById<ScrollView>(Resource.Id.dispatchScrollView);
    int posY = sv.ScrollY;

    outState.PutInt("scrollY", posY);
}

protected override void OnRestoreInstanceState(Bundle savedInstanceState)
{
    base.OnRestoreInstanceState(savedInstanceState);

    ScrollView sv = FindViewById<ScrollView>(Resource.Id.dispatchScrollView);
    int posY = savedInstanceState.GetInt("scrollY");

    sv.Post(new Runnable(new Action(() => sv.ScrollTo(0, posY))));
}

0

不要将滚动操作发送到下一个运行循环,而是可以在全局布局回调中滚动您的视图:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    sView.getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                sView.scrollTo(sViewX, sViewY);
            }
        }
    );
}

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