最初扩展的 BottomSheetDialog 不起作用
Initially expanded BottomSheetDialog not working
我有以下底部 sheet 对话框代码:
abstract class BaseMvpBottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
if (isFullscreen) { // true
dialog.setOnShowListener {
val bottomSheetDialog = it as BottomSheetDialog
bottomSheetDialog
.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
?.let { bottomSheetFl ->
from(bottomSheetFl).apply {
state = STATE_EXPANDED // This code is called, I've checked it with debugger
}
}
}
}
return dialog
}
以及以下布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/containerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorTransparent"
tools:background="#000000">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/closeIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/searchEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawableEnd="@drawable/ic_search_clear"
android:imeOptions="actionSearch"
android:inputType="text"
android:lines="1"
android:maxLines="1"
app:layout_constraintTop_toBottomOf="@id/closeIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/modelsRv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerLayout"
tools:listitem="@layout/view_item_model" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
我希望最初扩展对话框(并且布局采用所有垂直 space),但是当 RecyclerView
为空时,根本不需要 space:
我在 SO 上尝试过其他解决方案,但它们对我不起作用。
由于 RecyclerView
的高度已定义 MATCH_CONSTRAINTS
,我认为除了明确设置其高度外,没有其他方法可以满足您的要求。因此,为了达到所需的高度,我们可以从屏幕高度中减去 headerLayout
和设备状态栏的高度。
此外,我对您的代码做了一些更改:
- 我将视图的初始化设置到
setupDialog
中,并将全屏底部 sheet 的决定委托给子 class。
- 可以在
setupDialog
中设置透明背景,所以我们可以在xml
文件中删除根FrameLayout
以实现更小的视图层次。
BaseMvpBottomSheetFragment.kt
import android.app.Dialog
import android.content.Context
import android.view.View
import androidx.annotation.LayoutRes
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
abstract class BaseMvpBottomSheetFragment(
@LayoutRes private val layoutResId: Int
) : BottomSheetDialogFragment() {
protected val activityContext: Context by lazy { activity!!.applicationContext }
protected lateinit var rootView: View
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
rootView = View.inflate(activityContext, layoutResId, null)
dialog.setContentView(rootView)
onInitViews(rootView)
}
abstract fun onInitViews(rootView: View)
}
FullScreenBottomSheetDialogFragment.kt
import android.app.Dialog
import android.content.Context
import android.graphics.Point
import android.view.Display
import android.view.View
import android.view.WindowManager
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.android.synthetic.main.full_screen_bottom_sheet.view.*
class FullScreenBottomSheetDialogFragment : BaseMvpBottomSheetFragment(R.layout.full_screen_bottom_sheet) {
private var isFullscreen = true
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val parentView = rootView.parent as View
parentView.setBackgroundColor(ContextCompat.getColor(activityContext, R.color.colorTransparent))
val params = parentView.layoutParams as CoordinatorLayout.LayoutParams
val behavior = params.behavior
if (behavior is BottomSheetBehavior<*>) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
if (isFullscreen) {
behavior.peekHeight = screenSize(activityContext).y
}
}
}
override fun onInitViews(rootView: View) {
with(rootView) {
if (isFullscreen) {
headerLayout.post {
modelsRv.layoutParams.height =
screenSize(activityContext).y -
headerLayout.measuredHeight - // height of the header view
statusBarHeight(activityContext) // height of the status bar
modelsRv.requestLayout()
}
}
// do other initializations...
}
}
private fun screenSize(context: Context): Point {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display: Display? = windowManager.defaultDisplay
val point = Point()
display?.getSize(point)
return point
}
private fun statusBarHeight(context: Context): Int {
var result = 0
val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) result = context.resources.getDimensionPixelSize(resourceId)
return result
}
}
full_screen_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/closeIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/searchEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawableEnd="@drawable/ic_search_clear"
android:imeOptions="actionSearch"
android:inputType="text"
android:lines="1"
android:maxLines="1"
app:layout_constraintTop_toBottomOf="@id/closeIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/modelsRv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerLayout"
tools:listitem="@layout/view_item_model" />
</androidx.constraintlayout.widget.ConstraintLayout>
我有以下底部 sheet 对话框代码:
abstract class BaseMvpBottomSheetFragment : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
if (isFullscreen) { // true
dialog.setOnShowListener {
val bottomSheetDialog = it as BottomSheetDialog
bottomSheetDialog
.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
?.let { bottomSheetFl ->
from(bottomSheetFl).apply {
state = STATE_EXPANDED // This code is called, I've checked it with debugger
}
}
}
}
return dialog
}
以及以下布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/containerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorTransparent"
tools:background="#000000">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/closeIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/searchEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawableEnd="@drawable/ic_search_clear"
android:imeOptions="actionSearch"
android:inputType="text"
android:lines="1"
android:maxLines="1"
app:layout_constraintTop_toBottomOf="@id/closeIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/modelsRv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerLayout"
tools:listitem="@layout/view_item_model" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
我希望最初扩展对话框(并且布局采用所有垂直 space),但是当 RecyclerView
为空时,根本不需要 space:
我在 SO 上尝试过其他解决方案,但它们对我不起作用。
由于 RecyclerView
的高度已定义 MATCH_CONSTRAINTS
,我认为除了明确设置其高度外,没有其他方法可以满足您的要求。因此,为了达到所需的高度,我们可以从屏幕高度中减去 headerLayout
和设备状态栏的高度。
此外,我对您的代码做了一些更改:
- 我将视图的初始化设置到
setupDialog
中,并将全屏底部 sheet 的决定委托给子 class。 - 可以在
setupDialog
中设置透明背景,所以我们可以在xml
文件中删除根FrameLayout
以实现更小的视图层次。
BaseMvpBottomSheetFragment.kt
import android.app.Dialog
import android.content.Context
import android.view.View
import androidx.annotation.LayoutRes
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
abstract class BaseMvpBottomSheetFragment(
@LayoutRes private val layoutResId: Int
) : BottomSheetDialogFragment() {
protected val activityContext: Context by lazy { activity!!.applicationContext }
protected lateinit var rootView: View
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
rootView = View.inflate(activityContext, layoutResId, null)
dialog.setContentView(rootView)
onInitViews(rootView)
}
abstract fun onInitViews(rootView: View)
}
FullScreenBottomSheetDialogFragment.kt
import android.app.Dialog
import android.content.Context
import android.graphics.Point
import android.view.Display
import android.view.View
import android.view.WindowManager
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.android.synthetic.main.full_screen_bottom_sheet.view.*
class FullScreenBottomSheetDialogFragment : BaseMvpBottomSheetFragment(R.layout.full_screen_bottom_sheet) {
private var isFullscreen = true
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
val parentView = rootView.parent as View
parentView.setBackgroundColor(ContextCompat.getColor(activityContext, R.color.colorTransparent))
val params = parentView.layoutParams as CoordinatorLayout.LayoutParams
val behavior = params.behavior
if (behavior is BottomSheetBehavior<*>) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
if (isFullscreen) {
behavior.peekHeight = screenSize(activityContext).y
}
}
}
override fun onInitViews(rootView: View) {
with(rootView) {
if (isFullscreen) {
headerLayout.post {
modelsRv.layoutParams.height =
screenSize(activityContext).y -
headerLayout.measuredHeight - // height of the header view
statusBarHeight(activityContext) // height of the status bar
modelsRv.requestLayout()
}
}
// do other initializations...
}
}
private fun screenSize(context: Context): Point {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display: Display? = windowManager.defaultDisplay
val point = Point()
display?.getSize(point)
return point
}
private fun statusBarHeight(context: Context): Int {
var result = 0
val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) result = context.resources.getDimensionPixelSize(resourceId)
return result
}
}
full_screen_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/headerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/closeIv"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/searchEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawableEnd="@drawable/ic_search_clear"
android:imeOptions="actionSearch"
android:inputType="text"
android:lines="1"
android:maxLines="1"
app:layout_constraintTop_toBottomOf="@id/closeIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/modelsRv"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/headerLayout"
tools:listitem="@layout/view_item_model" />
</androidx.constraintlayout.widget.ConstraintLayout>