【问题标题】:Bottom sheet stays on screen when activity is recreated重新创建活动时,底部工作表保持在屏幕上
【发布时间】:2020-05-17 21:22:09
【问题描述】:

我在我的应用程序中添加了一个 BottomSheet。我在 onCreate 方法启动时将其隐藏。稍后它仅在需要时显示。我遇到的问题是当用户存在应用程序(底部工作表展开)并稍后返回应用程序时,Activity 被重新创建并且底部工作表保持在屏幕上 - 即使它在 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>

【问题讨论】:

  • BottomSheetFragment 或底部工作表行为?在行为的情况下,在使用工作表的布局中将 id 设置为根?
  • @AndreClassen 底部工作表行为。你的问题有点含糊,但无论我在哪里设置底部工作表的 ID,它都不起作用。

标签: android material-design


【解决方案1】:

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

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

即使活动经历了整个生命周期,您也无法将其隐藏在 onCreate 中,因为底部工作表状态已在 onRestoreInstanceState 中恢复

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

android:saveEnabled="false"

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

对我来说最好的解决方案是将底部工作表隐藏在onRestoreInstanceState 中。 不影响其他视图保存状态。

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

【讨论】:

    【解决方案2】:

    这是一个完整的 Kotlin 活动,试图实现该行为。 我已经通过关闭应用程序(然后让应用程序在后台运行)然后再次打开它来测试它。

    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
      }
    }
    

    这里我使用的是活动生命周期方法。

    下面是我的 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>
    

    【讨论】:

    • 确实有效,但我找到了问题的根本原因。它是分配给主容器的“根”ID。只需将 android:id="@+id/root" 添加到您的 CoordinatorLayout 中,它就不会在应用重新创建时隐藏。
    • 虽然 onResume 隐藏操作在这种情况下可以工作,但这不是我们想要的。我们只想隐藏活动重新创建的底部工作表,而不是每个活动 onResume。最后你的例子帮助我找出问题,所以赏金是你的:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 2022-11-30
    • 2013-09-15
    • 2012-09-25
    • 2020-10-13
    相关资源
    最近更新 更多