重新创建 activity 时,底部 sheet 保留在屏幕上

Bottom sheet stays on screen when activity is recreated

我在我的应用程序中添加了一个 BottomSheet。我在启动时将其隐藏在 onCreate 方法中。稍后它仅在需要时显示。我遇到的问题是当用户存在该应用程序(底部 sheet 已展开)然后返回到该应用程序时,Activity 被重新创建并且底部 sheet 留在屏幕上 -即使它在 onCreate 中将其设置为隐藏。

BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN

到目前为止我找到的唯一解决方案是覆盖 onRestoreInstanceState 回调,并且不要让 Activity 恢复它的状态。

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    // FIXME Temporary fix for BottomSheet not hiding on app recreate
    //super.onRestoreInstanceState(savedInstanceState)
}

我相信一定有更好的解决方案。可能导致此问题的原因是什么?

布局定义:

<androidx.coordinatorlayout.widget.CoordinatorLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/root"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout 
      android:id="@+id/myBottomSheet"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/white"
      app:behavior_hideable="true"
      app:behavior_peekHeight="90dp"
      app:layout_behavior="@string/bottom_sheet_behavior">

</androidx.coordinatorlayout.widget.CoordinatorLayout>

这是完整的 Kotlin activity 试图实现的行为。 我已经通过关闭应用程序(然后将应用程序 运行 留在后台)然后再次打开它来对其进行测试。

class MainActivity : AppCompatActivity() {

 override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN

hideBottomSheet.setOnClickListener {
  BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN
}

showBottomSheet.setOnClickListener {
  BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
     }
 }



   // this will work depending on the behaviour you want for your users
  override fun onResume() {
    super.onResume()
  //BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN
  }



   // This is enough for you, according to your description
  override fun onStart() {
    super.onStart()
    BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN
  }

  // this will work depending on the behaviour you want for your users
  override fun onRestart() {
    super.onRestart()
    // BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN
  }
}

我在这里使用 activity 生命周期方法。

下面是我的Xml文件,我添加了几个测试控件的按钮。

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

 <androidx.constraintlayout.widget.ConstraintLayout   xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/myBottomSheet"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/holo_blue_bright"
      app:behavior_hideable="true"
      app:behavior_peekHeight="90dp"
      app:layout_behavior="@string/bottom_sheet_behavior"/>

  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:orientation="horizontal"
      >


<Button
    android:id="@+id/showBottomSheet"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
      android:text="Show"
        />
    <Button
        android:id="@+id/hideBottomSheet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="hide"
        />
  </LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

虽然 Amos Korir 发布的答案完全正确,但我的主要问题是分配给 CoordinatorLayout 的 android:id="@+id/root"(Amos 的解决方案没有考虑到这一点)。

为视图分配一个 id 意味着当调用 onSaveInstanceState 时,Android 将保存给定视图的状态。在这种情况下,底部的 sheet 也会被保存,一旦 activity 被重新创建,它就会显示在屏幕上。

即使 activity 经历了整个生命周期,您也无法将其隐藏在 onCreate 中,因为底部 sheet 状态在 onRestoreInstanceState

因此,解决此问题的简单方法是将 saveEnabled 添加到底部 sheet 的父级。

android:saveEnabled="false"

当您将此行直接添加到底部 sheet 视图时,它似乎不起作用。 请记住,它也不会保存其他视图的状态。

对我来说最好的解决办法是把底部 sheet 隐藏在 onRestoreInstanceState 中。 不影响其他视图保存状态。

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    BottomSheetBehavior.from(myBottomSheet).state = BottomSheetBehavior.STATE_HIDDEN
}