Android: ScrollView 无意中滚动到顶部

Android: ScrollView scrolls to the top inadvertently

我有这样的布局:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ScrollView
        android:id="@+id/scroll_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:fillViewport="true" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            ... 
            other views 
            ... 

            <TextView
                android:id="@+id/text_view_that_can_change"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </RelativeLayout>
    </ScrollView>

    <include
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        layout="@layout/btns_ok_cancel" />

</RelativeLayout>

问题是当我将文本添加到最初为空时text_view_that_can_change - 我的ScrollView滚动到顶部.
当我在 ScrollView/RelativeLayout.

中设置某些视图的可见性时,会发生同样的问题 我可以使用 scrollView.scrollTo(0, yScroll) 将它向后滚动,但它给整个内容带来了可见的,我必须说,丑陋的混蛋。

有什么办法可以防止这种行为吗?

花了几个小时,这是我的发现。

滚动到顶部是因为内容更改导致内部 RelativeLayout 正在重新布局。

您应该添加几行来控制这种情况:
1) 声明 class 将保持滚动位置的成员:

int mSavedYScroll;

2)在主视图中添加GlobalLayoutListener(这里是fragment的主视图,无所谓):

    public View onCreateView(...) {
        mView = inflater.inflate(...);
        ...

        mView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (mSavedYScroll != 0) {
                    mScrollContainer.scrollTo(0, mSavedYScroll);
                    mSavedYScroll = 0;
                }
            }
        });
}

3) 当您执行某些操作(在您的代码中的任何位置)时可能会更改 ScrollView 的内容 - 只需保存当前滚动位置:

     mSavedYScroll = mScrollContainer.getScrollY();
     //DO SOMETHING THAT MAY CHANGE CONTENT OF mScrollContainer:
     ...

就是这样!