最初扩展的 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>