前言
BottomSheetDialog 是 Android 6.0 推出的新控件,即
Base class for Dialogs styled as a bottom sheet
基于Dialog样式的一个底部对话框
但原生控件可扩展性往往满足不了日常开发,于是自己基于它自定义一个Dialog,使用方便,可扩展性高,源码在文章最底部,不妨 Star 或 Fork
一、效果(图一 基础样式 图二 列表样式)
二、使用步骤
1.引入库
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2.代码
基础样式布局 bottom_dialog_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/top_corners_shape"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingHorizontal="30dp"
android:paddingVertical="25dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#2B2B2B"
android:textSize="18dp"
android:textStyle="bold"
android:visibility="gone" />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textColor="#2B2B2B"
android:textSize="24sp"
android:textStyle="bold"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_leftBtn"
android:layout_width="0dp"
android:layout_height="45dp"
android:layout_weight="1"
android:background="@drawable/dialog_left_btn_shape"
android:gravity="center"
android:textColor="#2B2B2B"
android:textSize="15dp"
android:textStyle="bold"
android:visibility="gone" />
<TextView
android:id="@+id/tv_rightBtn"
android:layout_width="0dp"
android:layout_height="45dp"
android:layout_marginStart="14dp"
android:layout_weight="1"
android:background="@drawable/dialog_right_btn_shape"
android:gravity="center"
android:textColor="#2984FF"
android:textSize="15sp"
android:textStyle="bold"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
列表样式布局 btn_bottom_dialog_layout.xml
<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="match_parent"
android:background="@drawable/top_corners_shape"
android:orientation="vertical"
android:paddingHorizontal="15dp">
<TextView
android:id="@+id/tv_bottom_dialog_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:gravity="center"
android:textColor="#2B2B2B"
android:textSize="15sp"
android:textStyle="bold"
android:visibility="gone" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#0d000000" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_btn_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
选项列表 btns_item_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="45dp">
<TextView
android:id="@+id/tv_dialog_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#2B2B2B"
android:textSize="15dp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_alignParentBottom="true"
android:background="#0d000000" />
</RelativeLayout>
列表样式实体类 DialogBtnData
public class DialogBtnData {
private int id;
private String title;
public DialogBtnData() {
}
public DialogBtnData(int id, String title) {
this.id = id;
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
列表适配器 BtnsBottomDialogAdapter
public class BtnsBottomDialogAdapter extends RecyclerView.Adapter<BtnsBottomDialogAdapter.VH> {
private static final String TAG = "BtnsBottomDialogAdapter";
private Context context;
private List<DialogBtnData> btnList;
private OnItemClickListener itemClickListener;
public BtnsBottomDialogAdapter(Context context, List<DialogBtnData> btnList) {
this.context = context;
this.btnList = btnList;
}
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.btns_item_layout, parent, false);
return new VH(v);
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
DialogBtnData curData = btnList.get(position);
if (curData == null || TextUtils.isEmpty(curData.getTitle())) {
return;
}
holder.itemView.setOnClickListener(v -> {
//item 点击事件
Log.d(TAG, "onClick position:" + position + ", data:" + curData);
if (itemClickListener != null) {
itemClickListener.onItemClick(v, position);
}
});
holder.titleTv.setText(curData.getTitle());
}
@Override
public int getItemCount() {
return btnList.size();
}
public void setOnItemClickListener(OnItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public static class VH extends RecyclerView.ViewHolder {
private TextView titleTv;
public VH(@NonNull View view) {
super(view);
titleTv = view.findViewById(R.id.tv_dialog_btn);
}
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
}
自定义 BottomDialog (此处有一个坑,当我在平板上运用的时候 横屏下 Dialog 会显示不全。需要手动上拉下,很是头痛 ,但问题不大,最后还是完美解决,代码中有记录)
/**
* 自定义底部弹出dialog
*/
public class BottomDialog implements View.OnClickListener, BtnsBottomDialogAdapter.OnItemClickListener {
private static final String TAG = "BottomDialog";
private Context context;
private BottomSheetDialog dialog;
private TextView titleTv;
private TextView contentTv;
private TextView leftBtnTv;
private TextView rightBtnTv;
private OnBtnClickListener listener;
private RecyclerView recyclerView;
private BtnsBottomDialogAdapter adapter;
private BtnsBottomDialogAdapter.OnItemClickListener listener1;
/**
* 基本样式
*
* @param context
*/
public BottomDialog(Context context) {
this.context = context;
dialog = new BottomSheetDialog(context, R.style.BottomSheetEdit);
View view = LayoutInflater.from(context).inflate(R.layout.bottom_dialog_layout, null);
dialog.setContentView(view);
// 将BottomSheetDialog背景设为透明
FrameLayout bottom = dialog.findViewById(R.id.design_bottom_sheet);
if (bottom != null) {
bottom.setBackgroundResource(android.R.color.transparent);
//解决BottomSheetDialog底部弹出框 横屏显示不全的问题
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottom);
/**
* 控制展开跟收缩
*
* STATE_EXPANDED 展开状态
* STATE_COLLAPSED 收缩状态
* STATE_DRAGGING 正在拖动状态
* STATE_HIDDEN 隐藏状态
*/
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
titleTv = view.findViewById(R.id.tv_title);
contentTv = view.findViewById(R.id.tv_content);
leftBtnTv = view.findViewById(R.id.tv_leftBtn);
rightBtnTv = view.findViewById(R.id.tv_rightBtn);
leftBtnTv.setOnClickListener(this);
rightBtnTv.setOnClickListener(this);
}
/**
* 列表样式
*
* @param context
* @param btnList
*/
public BottomDialog(Context context, List<DialogBtnData> btnList) {
dialog = new BottomSheetDialog(context, R.style.BottomSheetEdit);
View view = LayoutInflater.from(context).inflate(R.layout.btn_bottom_dialog_layout, null);
dialog.setContentView(view);
// 将BottomSheetDialog背景设为透明
FrameLayout bottom = dialog.findViewById(R.id.design_bottom_sheet);
if (bottom != null) {
bottom.setBackgroundResource(android.R.color.transparent);
//解决BottomSheetDialog底部弹出框 横屏显示不全的问题
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottom);
/**
* 控制展开跟收缩
*
* STATE_EXPANDED 展开状态
* STATE_COLLAPSED 收缩状态
* STATE_DRAGGING 正在拖动状态
* STATE_HIDDEN 隐藏状态
*/
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
recyclerView = view.findViewById(R.id.rcv_btn_list);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
adapter = new BtnsBottomDialogAdapter(context, btnList);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);
titleTv = view.findViewById(R.id.tv_bottom_dialog_title);
}
public void show() {
dialog.show();
}
public void dismiss() {
dialog.dismiss();
}
public BottomDialog setDismissListener(DialogInterface.OnDismissListener dismissListener) {
dialog.setOnDismissListener(dismissListener);
return this;
}
public BottomDialog setTitle(String title) {
if (!TextUtils.isEmpty(title)) {
titleTv.setVisibility(View.VISIBLE);
titleTv.setText(title);
}
return this;
}
public BottomDialog setContent(String content) {
if (!TextUtils.isEmpty(content)) {
contentTv.setVisibility(View.VISIBLE);
contentTv.setText(content);
}
return this;
}
public BottomDialog setLeftBtn(String btn) {
if (!TextUtils.isEmpty(btn)) {
leftBtnTv.setVisibility(View.VISIBLE);
leftBtnTv.setText(btn);
}
return this;
}
public BottomDialog setRightBtn(String btn) {
if (!TextUtils.isEmpty(btn)) {
rightBtnTv.setVisibility(View.VISIBLE);
rightBtnTv.setText(btn);
}
return this;
}
public BottomDialog setOnBtnClickListener(OnBtnClickListener listener) {
this.listener = listener;
return this;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_leftBtn:
dismiss();
if (listener != null) {
listener.onLeftBtnClick(v);
}
break;
case R.id.tv_rightBtn:
dismiss();
if (listener != null) {
listener.onRightBtnClick(v);
}
break;
default:
break;
}
}
public void setOnItemClickListener(BtnsBottomDialogAdapter.OnItemClickListener itemClickListener) {
this.listener1 = itemClickListener;
}
@Override
public void onItemClick(View view, int position) {
dismiss();
if (listener != null) {
listener1.onItemClick(view, position);
}
}
public interface OnBtnClickListener {
void onLeftBtnClick(View view);
void onRightBtnClick(View view);
}
}
最后终于要应用了
//普通底部弹出窗
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = false ? "您当前可升级更新到V" + 1.1 : "您当前已是最新版本";
BottomDialog dialog = new BottomDialog(MainActivity.this);
dialog.setTitle("检查更新").setContent(text).setLeftBtn("取消");
if (false) {
dialog.setRightBtn("点此下载最新版");
}
//自定义Dialog按钮监听
dialog.setOnBtnClickListener(new BottomDialog.OnBtnClickListener() {
@Override
public void onLeftBtnClick(View view) {
}
@Override
public void onRightBtnClick(View view) {
}
}).show();
}
});
//列表底部弹出窗
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<DialogBtnData> btnList = new ArrayList<>();
btnList.add(new DialogBtnData(1, "保存"));
btnList.add(new DialogBtnData(2, "取消"));
BottomDialog dialog = new BottomDialog(MainActivity.this, btnList);
dialog.setOnItemClickListener(new BtnsBottomDialogAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int pos) {
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
}
});
dialog.show();
}
});
总结
切记 遇到问题不要慌不要慌,实在没思路就去看源码,尤其自定义的控件,问题千奇百怪,要细心排查。就像这个横屏dialog显示不全的问题,源码上是这样的
@Override
protected void onStart() {
super.onStart();
if (behavior != null && behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
如果对你有所帮助的话,不妨 点赞收藏
如果你有什么疑问的话,不妨 评论私信
青山不改,绿水长流 ,有缘江湖再见 ~
源码地址:BottomSheetDialog