Please indicate the source of the reprint: http://blog.csdn.net/zhaoyanjun6/article/details/127967304
This article comes from [Zhao Yanjun's blog]
Article directory
- Effect
- BottomSheet
- BottomSheetDialog
- BottomSheetDialogFragment
- rounded corners
- remove background mask
- Set mask transparency
- Click outside the dialog, the dialog does not disappear
- Do not drag down
- Set the fixed height of the popup frame
- Content fills the full screen
- Monitor Expand Collapse
- Permanent View at the bottom
Effect
The MD-style bottom pop-up window is easier to use than custom dialog or popupwindow, and the function is more powerful.
In fact, in terms of subdivision, it is BottomSheet, BottomSheetDialog, BottomSheetDialogFragment
Code https://gitee.com/zhaoyanjun/bottomSheetDialogFragmentDemo
BottomSheet
The relationship with the main interface is the same level, and can be triggered by events. If the display height is set, it is also possible 拉出来
, and it will not affect the interaction of the main interface.
XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
<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>
</android.support.design.widget.CoordinatorLayout>
Notice,
- Here you need to coordinate the layout of the CoordinatorLayout package
- app:behavior_peekHeight displays the height, if not displayed, set it to 0
- app:layout_behavior indicates that this is a bottom_sheet
The above three conditions are all necessary.
the code
View bottomView = findViewById(R.id.ll_bottom_sheet);
bottomView.setOnClickListener(v -> {
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomView);
if (behavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
//如果是展开状态,则关闭,反之亦然
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else {
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
- STATE_COLLAPSED: Collapsed state
- STATE_EXPANDED: Expanded state
- STATE_DRAGGING : Transition state
- STATE_SETTLING: The short period of time when the view slides freely from the finger to when it finally stops
- 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 sliding down
BottomSheetDialog
半透明
It can be seen that there is a mask after the pop-up , which affects the interaction of the main interface at this time, which means that BottomSheetDialog
the priority at this time is higher than that of the main interface.
the code
public class MyBottomSheetDialog extends BottomSheetDialog {
public MyBottomSheetDialog(@NonNull Context context) {
super(context);
}
public MyBottomSheetDialog(@NonNull Context context, int theme) {
super(context, theme);
}
protected MyBottomSheetDialog(@NonNull Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
}
Show Dialog
MyBottomSheetDialog bottomSheetDialog = new MyBottomSheetDialog(this);
bottomSheetDialog.setContentView(R.layout.bottom_dialog_layout);
bottomSheetDialog.show();
bottom_dialog_layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical">
<TextView
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#aa8"
android:text="Bottom Dialog"
android:gravity="center"
android:layout_gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
A relatively simple way to use it, just instantiate it setContentView
and then call it show
.
This is just a display effect. In fact, the usage scenario may be more complicated, and some operations need to be done, etc. Therefore, you can also customize the dialog
inheritance from BottomSheetDialog
, and then process your own business logic.
BottomSheetDialogFragment
The effect is BottomSheetDialog
similar, and the code is DialogFragment
similar.
the code
public class MyDialogFragment extends BottomSheetDialogFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_dialog_fragment_layout, container, false);
return view;
}
}
bottom_dialog_fragment_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:background="#f00"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
show
MyDialogFragment dialog = new MyDialogFragment();
Bundle bundle = new Bundle();
dialog.setArguments(bundle);
dialog.show(getSupportFragmentManager(), "dialog_fragment");
But in actual development, our needs may not be satisfied, such as the above part 圆角效果
, 指定高度
etc.
rounded corners
First set the original background to be transparent
style.xml
<style name="MyBottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/BottomSheetStyleWrapper</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
</style>
<style name="BottomSheetStyleWrapper" parent="Widget.MaterialComponents.BottomSheet.Modal">
<item name="android:background">@android:color/transparent</item>
</style>
Set style in onCreate
public class MyDialogFragment extends BottomSheetDialogFragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NORMAL, R.style.MyBottomSheetDialog);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_dialog_fragment_layout, container, false);
return view;
}
}
Set on the view of the root layoutbackground
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="6dp"
android:background="@drawable/fragment_dialog_bg">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:background="#f00"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
Special attention: In addition to setting android:background
the property also needs to set android:padding
the property, otherwise the rounded corners will not be displayed.
fragment_dialog_bg
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
<solid android:color="@android:color/white" />
</shape>
remove background mask
Need to add attribute style
inandroid:backgroundDimEnabled
<!-- 没有蒙版的style-->
<style name="MyBottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/BottomSheetStyleWrapper</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
Set mask transparency
style
Add attribute in android:backgroundDimAmount
, attribute value range 0 - 1 .
- 0 : fully transparent
- 1: fully opaque
<style name="MyBottomSheetDialog2" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/BottomSheetStyleWrapper</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:backgroundDimAmount">0.4</item>
</style>
Click outside the dialog, the dialog does not disappear
Override onCreateDialog
the method , set setCanceledOnTouchOutside
the value to false
public class MyDialogFragment extends BottomSheetDialogFragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NORMAL, R.style.MyBottomSheetDialog);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.setCanceledOnTouchOutside(false);
return dialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_dialog_fragment_layout, container, false);
return view;
}
}
Do not drag down
bottomSheetBehavior.setHideable(false);
Specific usage method:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
if (dialog instanceof BottomSheetDialog) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
bottomSheetDialog.setOnShowListener(dialogInterface -> {
FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setHideable(false);
});
}
return dialog;
}
Set the fixed height of the popup frame
bottomSheetBehavior.setPeekHeight(1200);
use:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
if (dialog instanceof BottomSheetDialog) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
bottomSheetDialog.setOnShowListener(dialogInterface -> {
FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
bottomSheetBehavior.setPeekHeight(1200);
});
}
return dialog;
}
@Nullab
Content fills the full screen
When there is a lot of content, such as a recyclerView, we want the height of the dialog to expand to be full screen.
//默认展开
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
use
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
if (dialog instanceof BottomSheetDialog) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
bottomSheetDialog.setOnShowListener(dialogInterface -> {
FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
//默认展开
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
});
}
return dialog;
}
Monitor Expand Collapse
bottomSheetBehavior.setBottomSheetCallback()
use
public class MyDialogFragment extends BottomSheetDialogFragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NORMAL, R.style.MyBottomSheetDialog);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
if (dialog instanceof BottomSheetDialog) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
bottomSheetDialog.setOnShowListener(dialogInterface -> {
FrameLayout bottomSheet = bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet);
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
//默认展开
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View view, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_EXPANDED:
break;
case BottomSheetBehavior.STATE_COLLAPSED:
break;
case BottomSheetBehavior.STATE_DRAGGING:
break;
case BottomSheetBehavior.STATE_SETTLING:
break;
case BottomSheetBehavior.STATE_HIDDEN:
break;
}
}
@Override
public void onSlide(@NonNull View view, float v) {
}
});
});
}
return dialog;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_dialog_fragment_layout, container, false);
return view;
}
}
Permanent View at the bottom
It is difficult to realize the bottom resident layout in BottomSheetDialogFragment. Fortunately, some people have achieved it in a clever way.
https://github.com/dorianpavetic/StickyBottomSheet
Android: Sticky view at the bottom of bottom sheet dialog fragment