保存嵌套的滚动状态



我的应用程序围绕着底部包含4个选项卡的托运性。这些标签中的每一个都是一个片段,从一开始就添加了所有选项卡(未替换(,并且在敲击适当的选项卡时被隐藏/显示。

我的问题是,每当我更改选项卡时,滚动的状态就会丢失。表现出该问题的每个片段都使用android.support.v4.widget.NestedScrollView(示例见下文(。

注意:我使用recyclerview或ListView的片段由于某种原因保持其滚动状态。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <include layout="@layout/include_appbar_title" />
    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!-- Content -->
    </android.support.v4.widget.NestedScrollView>
</LinearLayout>

我读了几篇有关保存实例状态的文章(例如,一个,例如一个(,并且他们的解决方案要么在我的情况下不起作用,要么在实现我的情况下不实用,因为我有4-12个不同的片段I'D需要修改以使其正常工作。

拥有嵌套滚动视图的最佳方法是在片段上保持其滚动位置?

我在Inthecheesefactory上找到的一种解决方案是,默认情况下,片段保存了其状态(从EditText中的输入到滚动位置(,但前提XML元素。

在我的情况下,只需在我的NestedScrollview中添加ID解决了问题:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <include layout="@layout/include_appbar_title" />
    <android.support.v4.widget.NestedScrollView
        android:id="@+id/NestedScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!-- Content -->
    </android.support.v4.widget.NestedScrollView>
</LinearLayout>

查看nestedscrollview的实现,我们看到nestedscrollview的 scrolly 属性存储在其 sav_s> savedstate 中滚动位置。

// Source: NestedScrollView.java
@Override
protected Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState ss = new SavedState(superState);
    ss.scrollPosition = getScrollY();
    return ss;
}

因此,我确实同意Ramiro G.M.关于在跨配置变化的滚动位置的想法方面。在这种情况下

如果您使用的是片段和MVVM,那么我将嵌套的滚动位置保存在片段中的viewModel中 onviewDestroyed 方法。稍后,您可以在创建片段视图时通过livedata对象观察状态。

override fun onViewCreated(...) {
    mViewModel.scrollState.observe(viewLifecycleOwner, { scrollState ->
         binding.myNestedScrollView.scrollY = scrollState
    })
}
override fun onDestroyView() {
    val scrollState = binding.myNestedScrollView.scrollY
    mViewModel.setScrollState(scrollState)
    super.onDestroyView()
}

这只是一个简单的示例,但该概念是正确的。

您可以通过首先公开相应的方法来管理实例状态(包括卷轴状态(:

class SaveScrollNestedScrollViewer : NestedScrollView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attributes: AttributeSet) : super(context, attributes)
    constructor(context: Context, attributes: AttributeSet, defStyleAttr: Int) : super(context, attributes, defStyleAttr)

    public override fun onSaveInstanceState(): Parcelable? {
        return super.onSaveInstanceState()
    }
    public override fun onRestoreInstanceState(state: Parcelable?) {
        super.onRestoreInstanceState(state)
    }
}

然后在视图中使用它(YOUR_NAMESPACESaveScrollNestedScrollViewer类的名称空间(:

<YOUR_NAMESPACE.SaveScrollNestedScrollViewer
     android:id="@+id/my_scroll_viewer"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
</YOUR_NAMESPACE.SaveScrollNestedScrollViewer>

然后在显示它的活动中,根据需要保存/恢复状态。例如,如果要在导航后要恢复滚动位置,请使用以下内容:

class MyActivity : AppCompatActivity() {
    companion object {
        var myScrollViewerInstanceState: Parcelable? = null
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.my_activity)
        if (myScrollViewerInstanceState != null) {
            my_scroll_viewer.onRestoreInstanceState(myScrollViewerInstanceState)
        }
    }
    public override fun onPause() {
        super.onPause()
        myScrollViewerInstanceState = my_scroll_viewer.onSaveInstanceState()
    }
}

由于现在所有答案都弃用了,我会给大家一个新的选项。

  1. 创建一个变量以将嵌套的滚动视图保存在您的视图模型上:
class DummyViewModel : ViewModel() {
var estadoNestedSV:Int?=null
}
  1. 覆盖片段上的覆盖以在嵌套卷轴视图被破坏之前保存状态:
override fun onStop() {
        try {
            super.onStop()
            viewModel.estadoNestedSV = binding.nestedSV.scrollY
        } catch (e: Exception) {
            Log.i((activity as MainActivity).constantes.TAG_GENERAL, e.message!!)
        }
    }
  1. 通过覆盖范围的浏览在您的片段上创建视图后,恢复状态:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        try {
           //Check first if data exists to know if this load is a first time or if the device was rotated.
           if(viewModel.data.value != null)
           binding.nestedSVPelisDetalles.scrollY = viewModel.estadoNestedSV!!
            } catch (e: Exception) {
            Log.i((activity as MainActivity).constantes.TAG_GENERAL, e.message!!)
            }
    }

快乐编码!

最新更新