Android 底部 Sheet 上的静态页脚视图

Static Footer View On Android Bottom Sheet

我正在尝试在 Android 的底部sheet 上制作一个 静态页脚 。下面是我当前尝试的 GIF。请注意 sheet 完全展开时底部的 footer 文本。我希望此页脚文本 always 显示,无论 sheet 处于什么状态。(例如,如果 sheet 仅展开一半,则页脚仍应显示. 由于 sheet 正在 expanded/collapsed,页脚仍应始终显示等)我如何才能完成此行为?我看过这个:https://github.com/umano/AndroidSlidingUpPanel 但我更愿意得到一个不涉及任何外部库的香草 android 解决方案。

这是我现在的 XML。我认为问题是页脚锚定在视图底部,但视图底部只有在 sheet 完全展开时才可见。我想看看是否可以让页脚显示,而不管 sheet:

的状态如何
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:airbnb="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusableInTouchMode="true"
        android:orientation="vertical"
        android:id="@+id/linear_layout_container">

        <TextView
            android:id="@+id/header_text"
            android:layout_width="match_parent"
            android:text="Header"
            android:layout_height="36dp"
            android:layout_alignParentTop="true"
            />

        <com.airbnb.epoxy.EpoxyRecyclerView
            android:id="@+id/bottom_sheet_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            airbnb:layoutManager="LinearLayoutManager"
            android:layout_above="@+id/footer_text"
            android:layout_below="@+id/header_text"
            />
        <TextView
            android:id="@+id/footer_text"
            android:layout_width="match_parent"
            android:text="Footer"
            android:layout_height="36dp"
            android:layout_alignParentBottom="true"
            airbnb:layout_anchorGravity="bottom"
            />
    </RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

这是我的片段的样子。它只是一个显示底部 sheet 的空白片段: ContainerFragment.kt


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.airbnb.epoxy.EpoxyRecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog

class ContainerFragment : Fragment() {


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.container_fragment_layout, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.alpha = 0f
        val bottomSheet = BottomSheetDialog(requireContext())
        val bottomSheetView = LayoutInflater.from(context).inflate(R.layout.test_bottom_sheet_layout, null)
        bottomSheet.setContentView(bottomSheetView)
        bottomSheet.show()
        val epoxyRecyclerView : EpoxyRecyclerView = bottomSheetView.findViewById(R.id.bottom_sheet_recycler_view)
        epoxyRecyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        epoxyRecyclerView.withModels {
            (0..100).forEach {
                basicRow {
                    id(it)
                    title("This is the entry at index $it.")
                }
            }
        }
    }
    companion object {
        fun newInstance() = ContainerFragment()
    }
}

这是我的片段布局: container_fragment_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>

您需要以编程方式执行此操作,但实际上比看起来要简单。只需在 BottomSheet 滑动时调整 View 的位置即可。

  1. 将页脚视图添加为 BottomSheet 的直接子视图
<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#EECCCCCC"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <TextView
            android:id="@+id/pinned_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#500000FF"
            android:padding="16dp"
            android:text="Bottom" />
    </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
  1. 添加一个BottomSheetCallback并调整onSlide()中的translationY
BottomSheetBehavior.from(bottom_sheet).addBottomSheetCallback(
    object : BottomSheetBehavior.BottomSheetCallback() {

        override fun onSlide(bottomSheet: View, slideOffset: Float) {
            val bottomSheetVisibleHeight = bottomSheet.height - bottomSheet.top

            pinned_bottom.translationY =
                (bottomSheetVisibleHeight - pinned_bottom.height).toFloat()
        }

        override fun onStateChanged(bottomSheet: View, newState: Int) {
        }
    })

它运行顺利,因为你只是改变了 translationY。

您也可以使用此技术将视图固定在 BottomSheet 的中央:

pinned_center.translationY = (bottomSheetVisibleHeight - pinned_center.height) / 2f

我在 GitHub 上制作了一个示例项目来重现这两个用例(固定在中间和底部):https://github.com/dadouf/BottomSheetGravity

@DavidFerrand 基于使用 insead BottomSheetDialogFragment

val behavior: BottomSheetBehavior<*> = (dialog as BottomSheetDialog).behavior
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onStateChanged(bottomSheet: View, newState: Int) {}
    override fun onSlide(bottomSheet: View, slideOffset: Float) {
        binding.bottom.y = ((bottomSheet.parent as View).height - bottomSheet.top - binding.bottom.height).toFloat()
    }
}.apply {
    binding.root.post { onSlide(binding.root.parent as View, 0f) }
})