BottomSheetDialog use detailed explanation, set rounded corners, fixed height, default full screen, etc.

effect

Insert picture description here

The MD style is simpler and more powerful 底部弹窗than customizing dialogor popupwindowusing.

In fact broken down, it is BottomSheet, BottomSheetDialog,BottomSheetDialogFragment

BottomSheet

Insert picture description here

The main interface with the 同层级relationship that can trigger an event, set the display if there is 高度, then, may be 拉出来, and will not affect the interaction of the main interface.

XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
    tools:context="com.yechaoa.materialdesign.activity.BottomSheetActivity">

    <include
        android:id="@+id/include"
        layout="@layout/layout_toolbar" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:gravity="center"
        android:orientation="vertical">

        <Button
            android:id="@+id/btn_bottom_sheet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            android:text="BottomSheet"
            android:textAllCaps="false" />

        ...

    </LinearLayout>


    <LinearLayout
        android:id="@+id/ll_bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:behavior_peekHeight="80dp"
        app:layout_behavior="@string/bottom_sheet_behavior"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="@android:color/holo_red_light"
            android:gravity="center"
            android:text="上拉解锁隐藏功能"
            android:textColor="@color/white"
            android:textSize="20sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="@android:color/holo_blue_light"
            android:gravity="center"
            android:text="a"
            android:textSize="20sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="@android:color/holo_orange_dark"
            android:gravity="center"
            android:text="b"
            android:textSize="20sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:background="@android:color/holo_green_light"
            android:gravity="center"
            android:text="c"
            android:textSize="20sp" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

  • Note that the layout CoordinatorLayoutpackage needs to be coordinated here
  • app:behavior_peekHeightDisplay height, if not displayed, set it to 0
  • app:layout_behavior Mark this is abottom_sheet

The above three conditions are all 必须true.

Code

        btn_bottom_sheet.setOnClickListener {
    
    
            val behavior = BottomSheetBehavior.from(ll_bottom_sheet)
            if (behavior.state == BottomSheetBehavior.STATE_EXPANDED) {
    
    
                //如果是展开状态,则关闭,反之亦然
                behavior.state = BottomSheetBehavior.STATE_COLLAPSED
            } else {
    
    
                behavior.state = BottomSheetBehavior.STATE_EXPANDED
            }
        }

  • STATE_COLLAPSED: Collapsed state
  • STATE_EXPANDED: Expanded state
  • STATE_DRAGGING: transition state
  • STATE_SETTLING: This short period of time from the free sliding of the view from the finger to the final stop
  • STATE_HIDDEN: There is no such state by default (this state can be enabled through app:behavior_hideable), after enabling the user will be able to completely hide the bottom sheet by swiping down

BottomSheetDialog

Insert picture description here
You can see that there is a 半透明mask after it pops up . This time it affects the main interface interaction, which means that BottomSheetDialogthe priority at this time is higher than the main interface.

Code

            val bottomSheetDialog = BottomSheetDialog(this)
            bottomSheetDialog.setContentView(R.layout.dialog_bottom_sheet)
            bottomSheetDialog.show()

dialog_bottom_sheet:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingTop="80dp"
    android:paddingBottom="80dp"
    android:text="BottomSheetDialog"
    android:textSize="30sp"
    android:textStyle="bold" />

The simpler way to use it is to directly instantiate setContentViewand then call showit.

This is just a display effect. In fact, the use scene may be more complicated, and some operations need to be done. Therefore, you can also customize the dialog and inherit from BottomSheetDialog, and then process your own business logic.

such as:

class MyDialog(context: Context) : BottomSheetDialog(context) {
    
    

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
    }
  
}

BottomSheetDialogFragment

Insert picture description here
The effect is BottomSheetDialogsimilar, and the code is DialogFragmentsimilar.

Code

class MyBottomSheetDialog : BottomSheetDialogFragment() {
    
    

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    
    
        val dialog = super.onCreateDialog(savedInstanceState)
        val view = LayoutInflater.from(context).inflate(R.layout.dialog_my_bottom_sheet, null)
        dialog.setContentView(view)
        initView(view)
        return dialog
    }

    private fun initView(rootView: View) {
    
    
        //do something
        rootView.tv_cancel.setOnClickListener {
    
     dismiss() }

    }
}

dialogIntroduce the layout when creating , and then setContentViewyou can.

transfer:

MyBottomSheetDialog().show(supportFragmentManager, "MyBottomSheetDialog")
  • FragmentManager
  • tag

But in actual development, our needs may not be satisfied, such as the above part 圆角效果, 指定高度etc.

Rounded corners

  • First set the original background transparent

style.xml

    <!--实现BottomSheetDialog圆角效果-->
    <style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item>
    </style>
    <style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@android:color/transparent</item>
    </style>
  • Set style in onCreate
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NORMAL, R.style.BottomSheetDialog)
    }
  • Set our own style

In 根布局的viewthe Settingsbackground

android:background="@drawable/shape_sheet_dialog_bg"

shape_sheet_dialog_bg

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:topLeftRadius="15dp"
        android:topRightRadius="15dp" />
    <solid android:color="@color/white" />
</shape>

Remove background shadow

Insert picture description here
You can see if there is no shadow mask or style, just set backgroundDimEnabledit falseto

    <!--实现BottomSheetDialog圆角效果 且无背景阴影-->
    <style name="BottomSheetDialogBg" parent="Theme.Design.Light.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>
    <style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@android:color/transparent</item>
    </style>

Set fixed height

Insert picture description here
You can see that this pop-up window is not fully expanded at the beginning, but it can be pulled out.

Code

    override fun onStart() {
    
    
        super.onStart()
        //拿到系统的 bottom_sheet
        val view: FrameLayout = dialog?.findViewById(R.id.design_bottom_sheet)!!
        //获取behavior
        val behavior = BottomSheetBehavior.from(view)
        //设置弹出高度
        behavior.peekHeight = 350
    }

There is a peekHeightproperty to set the height, but this api is not open to us, but there is a solution

We can view setContentViewthe source code of bottomSheetDialog.

  @Override
  public void setContentView(@LayoutRes int layoutResId) {
    
    
    super.setContentView(wrapInBottomSheet(layoutResId, null, null));
  }

Called here wrapInBottomSheet, continue to explore

  private View wrapInBottomSheet(int layoutResId, @Nullable View view, @Nullable ViewGroup.LayoutParams params) {
    
    
    ensureContainerAndBehavior(); 
    ...
    return container;
  }

You don’t need to look at the extra, just explore the ensureContainerAndBehavior();method directly

  /** Creates the container layout which must exist to find the behavior */
  private FrameLayout ensureContainerAndBehavior() {
    
    
    if (container == null) {
    
    
      container =
          (FrameLayout) View.inflate(getContext(), R.layout.design_bottom_sheet_dialog, null);

      FrameLayout bottomSheet = (FrameLayout) container.findViewById(R.id.design_bottom_sheet);
      behavior = BottomSheetBehavior.from(bottomSheet);
      behavior.addBottomSheetCallback(bottomSheetCallback);
      behavior.setHideable(cancelable);
    }
    return container;
  }

At this point, we can see how the source code is obtained behavior, and behaviorafter obtaining it , we can call to peekHeightset the height.

Set the default full screen display

Now that I have the above method, do I have an idea? Then someone said, I set the height to full screen and it will be finished.

In fact, it is really not good, BottomSheetDialogFragmentonly the actual height is displayed, that is, the layout 有效高度, even the root layout height match_parentis not good.

Since our own view doesn’t work, let’s start with BottomSheetDialogFragment itself. Remember dialog?.findViewById(R.id.design_bottom_sheet)!!the view we got through above ? Let’s try to set the height of this view.

view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT

Look at the effect
Insert picture description here
First of all, like the default effect, when the content is greater than or equal to the full screen, it will first reach a height, that is, the height of the above effect, and then continue to slide up to fill the full screen.

Although it is not the expected effect, since you can still swipe up to the full screen, it means that the height we set is effective, but there is no one-time expansion. Remember the state mentioned earlier state, set it and try

behavior.state = BottomSheetBehavior.STATE_EXPANDED

Look at the effect
Insert picture description here
. It’s okay, this is the full screen directly, but when I pull it down, I found that it was not put away at one time, but it was displayed when it stopped at full screen 默认位置. Let’s try setting the height to full screen.

behavior.peekHeight = 3000

The actual height can be calculated by yourself

Final code

    override fun onStart() {
    
    
        super.onStart()
        //拿到系统的 bottom_sheet
        val view: FrameLayout = dialog?.findViewById(R.id.design_bottom_sheet)!!
        //设置view高度
        view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
        //获取behavior
        val behavior = BottomSheetBehavior.from(view)
        //设置弹出高度
        behavior.peekHeight = 3000
        //设置展开状态
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
    }

See the final result
Insert picture description here

The effect is ok, but there is also a little shortcoming. We can close it when the distance we pull down is almost to the bottom, so it is recommended to add the closing operation in the pop-up window.

MonitorExpandCollapse

        behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
    
    
            
            override fun onStateChanged(bottomSheet: View, newState: Int) {
    
    
                when(newState){
    
    
                    BottomSheetBehavior.STATE_EXPANDED->{
    
    }
                    BottomSheetBehavior.STATE_COLLAPSED->{
    
    }
                    BottomSheetBehavior.STATE_DRAGGING->{
    
    }
                    BottomSheetBehavior.STATE_SETTLING->{
    
    }
                    BottomSheetBehavior.STATE_HIDDEN->{
    
    }
                }
            }

            override fun onSlide(bottomSheet: View, slideOffset: Float) {
    
    

            }

        })

It can be written in the dialog or thrown out by the interface.

github

https://github.com/yechaoa/MaterialDesign


Ok, so far the BottomSheetDialogrelated functions are completely demonstrated.

If it works for you, please give me a thumbs up ^ _ ^

Guess you like

Origin blog.csdn.net/yechaoa/article/details/110134991