如何创建如附件所示且具备默认、拖动、关闭分阶段交互效果的BottomSheetDialogFragment
Got it, let's build that BottomSheetDialogFragment that behaves exactly like your sample—with clear default, dragged, and closed states. Here's a step-by-step implementation tailored to your needs:
First, define the layout for your bottom sheet (res/layout/bottom_sheet_content.xml). Adjust the content to match your sample's UI:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp" android:background="@drawable/bottom_sheet_rounded_bg"> <!-- Add your sample UI elements here (title, buttons, etc.) --> <TextView android:id="@+id/state_indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Default State" android:textSize="18sp" android:textStyle="bold"/> <!-- Add more content as needed --> </LinearLayout>
Note: Create a bottom_sheet_rounded_bg.xml drawable for rounded top corners to match typical bottom sheet styling.
Create a subclass of BottomSheetDialogFragment and wire up state handling using BottomSheetBehavior to control and listen to state changes:
import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment class CustomBottomSheetDialog : BottomSheetDialogFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.bottom_sheet_content, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Get the core bottom sheet view and its behavior val bottomSheet = dialog?.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) val behavior = BottomSheetBehavior.from(bottomSheet!!) // Configure default state: set peek height (visible portion when collapsed) behavior.peekHeight = 300 // Adjust this value to match your sample's default visible height behavior.isHideable = true // Enable dragging to close // Listen for state transitions behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { val stateText = view.findViewById<TextView>(R.id.state_indicator) when(newState) { BottomSheetBehavior.STATE_COLLAPSED -> { // Default state: reset UI to initial state stateText.text = "Default State" } BottomSheetBehavior.STATE_DRAGGING -> { // Dragging state: update UI to show active interaction stateText.text = "Dragging State" } BottomSheetBehavior.STATE_HIDDEN -> { // Closed state: dismiss the dialog completely dismiss() } // Optional: Handle expanded state if your sample uses it BottomSheetBehavior.STATE_EXPANDED -> { stateText.text = "Expanded State" } } } override fun onSlide(bottomSheet: View, slideOffset: Float) { // Add smooth UI transitions during dragging (e.g., opacity, scaling) // Example: Fade out as user drags toward closing if (slideOffset < 0) { bottomSheet.alpha = 1 + slideOffset } } }) } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { // Apply custom theme to match sample styling val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog dialog.context.setTheme(R.style.CustomBottomSheetDialogTheme) return dialog } }
Add a custom theme to styles.xml to match your sample's visual style:
<style name="CustomBottomSheetDialogTheme" parent="Theme.MaterialComponents.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/CustomBottomSheetStyle</item> <item name="android:windowIsFloating">false</item> </style> <style name="CustomBottomSheetStyle" parent="Widget.MaterialComponents.BottomSheet.Modal"> <item name="android:background">@drawable/bottom_sheet_rounded_bg</item> <item name="behavior_peekHeight">300dp</item> <item name="behavior_hideable">true</item> </style>
To display your bottom sheet from an Activity or Fragment:
val bottomSheet = CustomBottomSheetDialog() bottomSheet.show(supportFragmentManager, "CustomBottomSheet")
Key Notes:
- Adjust
peekHeightto match your sample's default visible height (convert dp to pixels programmatically if you need dynamic sizing). - Modify the
onSlidecallback to add any visual transitions (like scaling, fading) that match your sample's dragged state behavior. - If your sample requires a custom drag threshold for closing, extend
BottomSheetBehaviorto override the hide trigger logic.
内容的提问来源于stack exchange,提问作者Chirag Thummar

