preface
In the past, if you wanted a Dialog box to pop up at the bottom, you would inherit the Dialog, set the layout, set the position, set the height and width, and if you wanted to add a bottom-to-top animation, you would need to create a new animation file, but later, We have the official offer BottomSheetDialogFragment, BottomSheetDialog, bottomSheetBehavior these classes, a few lines of code can achieve the effect.
As shown below, you can simply create a Dialog that pops up at the bottom.
var bottomSheetDialog = BottomSheetDialog(this)
bottomSheetDialog.setContentView(R.layout.dialog)
bottomSheetDialog.show()
Copy the code
You can also use BottomSheetDialogFragment, BottomSheetDialogFragment inherited from DialogFragment, we can rewrite the onCreateDialog method when needed, returns the custom Dialog, He also returns BottomSheetDialog by default,
public class BottomSheetDialogFragment extends AppCompatDialogFragment {
private boolean waitingForDismissAllowingStateLoss;
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return newBottomSheetDialog(getContext(), getTheme()); }... }Copy the code
Drag and drop
If the view has a lot of things to display, the default is to show only one part of the view and drag and drop the other part up to display. To see how this works, you can continue down. In this case, just create a new dialog layout with the height set to match_parent.
class MemberBottomSheetDialog : BottomSheetDialogFragment(a){
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState: Bundle? ): View? = inflater.inflate(R.layout.dialog, container, false)
}
MemberBottomSheetDialog().show(supportFragmentManager,"TAG")
Copy the code
<RelativeLayout 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:background="#ffffff"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</RelativeLayout>
Copy the code
But you’ll notice that the content is only displayed when the root layout is RelativeLayout.
Modify the height
Due to BottomSheetDialogFragment use BottomSheetDialog, he is the default height calculation parentHeight – parentWidth * 9/16, but his foreign provides a method to us, To set the initial state, as shown below:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
varbottomSheetDialog = BottomSheetDialog(context!!) ; bottomSheetDialog.behavior.peekHeight=100;
return bottomSheetDialog
}
Copy the code
Open by default
Another problem is that the default is not, if you want to, also is the full screen, you can set the state for BottomSheetBehavior. STATE_EXPANDED.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (dialog is BottomSheetDialog) {
val behaviour = (dialog as BottomSheetDialog).behavior behaviour.state = BottomSheetBehavior.STATE_EXPANDED }
}
Copy the code
Ban on drag and drop
SetDraggable sets whether draggable can be collapsed/expanded by dragging. When dragging is disabled, the application needs to implement a custom way to expand/collapse the dialog box.
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
bottomSheetDialog.behavior.isDraggable=false
return bottomSheetDialog
}
Copy the code
The background remains dark
By default, when the dialog box pops up, it will be dark, but you can just add a style.
<style name="myDialog" parent="Theme.MaterialComponents.BottomSheetDialog">
<item name="android:backgroundDimEnabled">false</item>
</style>
Copy the code
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
returnBottomSheetDialog(context!! , R.style.myDialog) }Copy the code
Monitor the scroll
Sometimes need to drag up time to do some linkage, you need to get the value of the sliding dialog by behaviors. AddBottomSheetCallback.
SlideOffset is between 0 and 1, 0 by default, 1 when it slides to the top, -1 when it disappears,
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
bottomSheetDialog.behavior.addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
Log.i(TAG, "onStateChanged: ")}override fun onSlide(bottomSheet: View, slideOffset: Float) {
Log.i(TAG, "onSlide: ${slideOffset}")}})return bottomSheetDialog
}
Copy the code
How do you calculate when you drag up?
This problem is very simple, it does internal drag using ViewDragHelper, so when we can’t drag up, there are two ways to use ViewDragHelper, one is to return false in tryCaptureView, 2 it is in the clampViewPositionVertical returns a value, the value returned to one of the biggest drag, when we drag and drop to the top, will not be able to continue upward.
The default height is parentHeight – parentWidth * 9/16, but if our View is smaller than this value, then the final height is the smallest, that is, the value of the View, so that the dialog box is already displayed. Why do we have to move it up?
But if our View height is greater than this value, it will take parentHeight – parentWidth * 9/16 as the height of the Dialog. How much space can we move up? The answer is View height -parentHeight – parentWidth * 9/16.
For example, on my phone, parentHeight is 2159, so if View is 1600, then I can move it up by 40px by defining the fitToContentsOffset variable, which is parentHeight childHeight. The free space of the screen, when dragging up trigger clampViewPositionVertical method, he returned to the value of the vertical position, as a new so when drag and drop to the top, will return fitToContentsOffset.
BottomSheetBehavior implements the bottom Dialog
BottomSheetDialog is also implemented using BottomSheetBehavior. First, you define a layout. Note that the root layout can only be CoordinatorLayout.
<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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open" />
</LinearLayout>
<LinearLayout
android:background="@color/cardview_dark_background"
android:id="@+id/design_bottom_sheet1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="300dp"
app:elevation="6dp"
app:layout_behavior="@string/bottom_sheet_behavior"></LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Copy the code
var bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.design_bottom_sheet1));
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
findViewById<View>(R.id.bt).setOnClickListener {
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
} else if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
}
Copy the code