重新创建 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
}
我在我的应用程序中添加了一个 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
}