网站首页 > 博客文章 正文
日常开发中或多或少都会使用到Dialog,每次都需要自定义继承Dialog,写多了不胜其烦,今天我们对Dialog做个封装,可通过链式构建,以ViewDataBinding方式设置ContentView(之后会扩展支持通过View方式设置ContentView,类似的封装可看我的另外一篇文章Android通用PopupWindow的封装)。
先看使用示例:
这里的layout_sorting_filter是我们自定义View的xml文件,LayoutSortingFilterBinding是对应的ViewDataBinding
GeneralDialog mGeneralDialog = new GeneralDialog.Builder<LayoutSortingFilterBinding>()
.layoutId(R.layout.layout_sorting_filter)
.intercept(new GeneralDialog.GeneralDialogEvent<LayoutSortingFilterBinding>() {
@Override
public void getView(LayoutSortingFilterBinding mBinding) {
/*在这里可做初始化相关操作*/
}
})
.width(WindowManager.LayoutParams.MATCH_PARENT)
.height(WindowManager.LayoutParams.WRAP_CONTENT)
.setCanceledOnTouchOutside(true)
.gravity(Gravity.BOTTOM)
.addClickViews(R.id.tv_cancel, R.id.tv_sure)
.callbackClickOn(new GeneralDialog.OnClickCallback() {
@Override
public void onClick(GeneralDialog generalDialog, View view) {
int id = view.getId();
if (id == R.id.tv_cancel) {
/*点击了取消*/
} else if (id == R.id.tv_sure) {
/*点击了确定*/
}
generalDialog.dismiss();
}
}).Build(this);
Window mWindow = mGeneralDialog.getWindow();
/*设置窗口出现和消失的动画*/
if (mWindow != null) {
mWindow.setWindowAnimations(R.style.anim_slide);
}
mGeneralDialog.show();
addClickViews方法是设置点击事件监听的,支持设置多个View,如仅需设置一个也可通过方法addClickView(int id),如:
GeneralDialog mGeneralDialog = new GeneralDialog.Builder<LayoutSortingFilterBinding>()
.layoutId(R.layout.layout_sorting_filter)
.intercept(new GeneralDialog.GeneralDialogEvent<LayoutSortingFilterBinding>() {
@Override
public void getView(LayoutSortingFilterBinding mBinding) {
/*在这里可做初始化相关操作*/
}
})
.width(WindowManager.LayoutParams.MATCH_PARENT)
.height(WindowManager.LayoutParams.WRAP_CONTENT)
.setCanceledOnTouchOutside(true)
.gravity(Gravity.BOTTOM)
.addClickView(R.id.tv_sure)
.callbackClickOn(new GeneralDialog.OnClickCallback() {
@Override
public void onClick(GeneralDialog generalDialog, View view) {
/*点击了确定*/
generalDialog.dismiss();
}
}).Build(this);
Window mWindow = mGeneralDialog.getWindow();
/*设置窗口出现和消失的动画*/
if (mWindow != null) {
mWindow.setWindowAnimations(R.style.anim_slide);
}
mGeneralDialog.show();
GeneralDialog完整的代码如下:
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import java.util.ArrayList;
/**
* 作者:可口可乐的可乐 on 2019/9/02 14:45
* Email : 1966353889@qq.com
* Describe:通用Dialog(用于各种提示或对话框形式的操作)
* update on 2020/3/02 16:52
*/
public class GeneralDialog<T extends ViewDataBinding> extends Dialog implements View.OnClickListener {
/**
* Dialog layout视图
*/
private T mBinding;
/**
* 点击事件监听(不带layout视图)
*/
private OnClickCallback mClickEvent;
/**
* 点击事件监听(带layout视图)
*/
private OnBindingClickCallback<T> mBindingClickEvent;
@SuppressWarnings("unchecked")
private GeneralDialog(Context context, Builder builder) {
this(context);
mBinding = DataBindingUtil.inflate(getLayoutInflater(), builder.layoutId, null, false);
setContentView(mBinding.getRoot());
initSetting(builder.mDialogSet, builder.mCancelable, builder.canceledOnTouchOutside);
intercept(builder.event);
setClickEvent(builder.clickViews);
mClickEvent = builder.mClickEvent;
mBindingClickEvent = builder.mBindingClickEvent;
}
private GeneralDialog(@NonNull Context context) {
super(context, R.style.DarkBackgroundDialog);
}
/**
* 窗体的一些设置
*
* @param mDialogSet 窗体的设置类
* @param mCancelable 是否可取消(按物理返回键)
* @param canceledOnTouchOutside 是否可点击外部取消
**/
private void initSetting(DialogSet mDialogSet, boolean mCancelable, boolean canceledOnTouchOutside) {
Window window = getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
if (mDialogSet != null) {
lp.width = mDialogSet.width;
lp.height = mDialogSet.height;
lp.gravity = mDialogSet.gravity;
setCancelable(mDialogSet.mCancelable);
setCanceledOnTouchOutside(mDialogSet.canceledOnTouchOutside);
} else {
lp.width = getContext().getResources().getDimensionPixelOffset(R.dimen.x812);
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.CENTER;
setCancelable(mCancelable);
setCanceledOnTouchOutside(canceledOnTouchOutside);
}
window.setAttributes(lp);
}
/**
* 设置点击事件
*
* @param clickViews 需要设置点击事件监听的View的id集合
*/
private void setClickEvent(ArrayList<Integer> clickViews) {
if (clickViews != null && mBinding != null) {
for (int id : clickViews) {
if (mBinding.getRoot().findViewById(id) != null) {
mBinding.getRoot().findViewById(id).setOnClickListener(this);
}
}
}
}
/**
* 拦截,可根据返回的ViewDataBinding实现需要的逻辑
*
* @param event 回调事件,可返回当前Dialog视图
*/
private void intercept(GeneralDialogEvent<T> event) {
if (event != null && mBinding != null) {
event.getView(mBinding);
}
}
/**
* 设置点击事件回调
*
* @param event 回调事件
*/
private void clickCallback(OnClickCallback event) {
if (event != null && mBinding != null) {
mClickEvent = event;
}
}
/**
* 设置点击事件回调
*
* @param event 回调事件
*/
private void bindingClickCallback(OnBindingClickCallback<T> event) {
if (event != null && mBinding != null) {
mBindingClickEvent = event;
}
}
@Override
public void onClick(View v) {
if (mClickEvent != null) {
mClickEvent.onClick(this, v);
}
if (mBindingClickEvent != null) {
mBindingClickEvent.onClick(this, mBinding, v);
}
}
public interface GeneralDialogEvent<T> {
/**
* 返回Dialog的layout视图(DataBinding类型)
*/
void getView(T mBinding);
}
public interface OnClickCallback {
/**
* 点击事件回调
*
* @param dialog dialog本身
* @param v 产生点击事件的View
*/
void onClick(GeneralDialog dialog, View v);
}
public interface OnBindingClickCallback<T> {
/**
* 点击事件回调
*
* @param dialog dialog本身
* @param mBinding dialog的layout视图(DataBinding类型)
* @param v 产生点击事件的View
*/
void onClick(GeneralDialog dialog, T mBinding, View v);
}
public static class Builder<T extends ViewDataBinding> {
/**
* Dialog的布局文件id
*/
private int layoutId;
/**
* 用于返回Dialog的layout视图(DataBinding类型)
*/
private GeneralDialogEvent event;
/**
* 点击事件监听(不带layout视图)
*/
private OnClickCallback mClickEvent;
/**
* 点击事件监听(带layout视图)
*/
private OnBindingClickCallback mBindingClickEvent;
/**
* 设置此对话框在触摸窗口外时是否被取消,优先级比cancel高
*/
private DialogSet mDialogSet;
/**
* 设置此对话框在触摸窗口外时是否被取消,优先级比mDialogSet低
*/
private boolean canceledOnTouchOutside = true;
/**
* 设置此对话框在能否被按返回键销毁,优先级比mDialogSet低
*/
private boolean mCancelable;
/**
* 存储所有的带点击事件的View id集合
*/
private ArrayList<Integer> clickViews;
/**
* 设置Dialog的布局文件id
*
* @param layoutId 布局文件id
*/
public Builder layoutId(int layoutId) {
this.layoutId = layoutId;
return this;
}
/**
* 设置Dialog的宽
*
* @param width 宽
*/
public Builder width(int width) {
if (mDialogSet == null) {
mDialogSet = new DialogSet();
}
mDialogSet.width = width;
return this;
}
/**
* 设置Dialog的高
*
* @param height 高
*/
public Builder height(int height) {
if (mDialogSet == null) {
mDialogSet = new DialogSet();
}
mDialogSet.height = height;
return this;
}
/**
* 设置Dialog的对齐方式
*
* @param gravity 对齐方式
*/
public Builder gravity(int gravity) {
if (mDialogSet == null) {
mDialogSet = new DialogSet();
}
mDialogSet.gravity = gravity;
return this;
}
/**
* 设置Dialog点击外部是否可以取消
*
* @param cancel 是否可取消
*/
public Builder setCanceledOnTouchOutside(boolean cancel) {
if (mDialogSet == null) {
mDialogSet = new DialogSet();
}
mDialogSet.canceledOnTouchOutside = cancel;
this.canceledOnTouchOutside = cancel;
return this;
}
/**
* 设置Dialog是否可以取消(按物理返回键)
*
* @param cancel 是否可取消
*/
public Builder setCancelable(boolean cancel) {
if (mDialogSet == null) {
mDialogSet = new DialogSet();
}
mDialogSet.mCancelable = cancel;
this.mCancelable = cancel;
if (!cancel) {
/*this.canceledOnTouchOutside默认为true,当设置mCancelable为false时,设置canceledOnTouchOutside会影响
* mCancelable的值,所以如果设置了mCancelable为false,则canceledOnTouchOutside先要设置为false
* */
mDialogSet.canceledOnTouchOutside = false;
this.canceledOnTouchOutside = false;
}
return this;
}
/**
* 拦截事件
*/
public Builder intercept(GeneralDialogEvent event) {
this.event = event;
return this;
}
/**
* 点击事件回调
*/
public Builder callbackClickOn(OnClickCallback event) {
this.mClickEvent = event;
return this;
}
/**
* 点击事件回调
*/
public Builder bindingCallbackClickOn(OnBindingClickCallback event) {
this.mBindingClickEvent = event;
return this;
}
/**
* 增加点击事件
*
* @param id 点击监听的View的id
*/
public Builder addClickView(int id) {
if (clickViews == null) {
clickViews = new ArrayList<>();
}
clickViews.add(id);
return this;
}
/**
* 增加点击事件
*
* @param ids 点击监听的Views的id
*/
public Builder addClickViews(int... ids) {
if (ids != null && ids.length > 0) {
if (clickViews == null) {
clickViews = new ArrayList<>();
}
for (int id : ids) {
clickViews.add(id);
}
}
return this;
}
/**
* 返回带DialogSet的GeneralDialog
*
* @param context 上下文
*/
public GeneralDialog Build(Context context) {
if (mDialogSet == null) {
throw new RuntimeException("未设置窗体大小和位置信息");
}
return new GeneralDialog<T>(context, this);
}
/**
* 返回不带DialogSet的GeneralDialog
*
* @param context 上下文
*/
public GeneralDialog getDefault(Context context) {
if (mDialogSet != null) {
mDialogSet = null;
}
return new GeneralDialog<T>(context, this);
}
}
/**
* 窗体设置类
*/
public static class DialogSet {
/**
* Dialog的宽
*/
private int width;
/**
* Dialog的高
*/
private int height;
/**
* Dialog对齐模式
*/
private int gravity;
/**
* 点击外部是否能取消
*/
boolean canceledOnTouchOutside;
/**
* 是否能取消
*/
boolean mCancelable;
}
}
用到的R.style.DarkBackgroundDialog对应如下:
<resources>
<style name="DarkBackgroundDialog" parent="@android:style/Theme.Dialog">
<!-- 是否漂现在activity上 -->
<item name="android:windowIsFloating">true</item>
<!-- 是否隐藏标题 -->
<item name="android:windowNoTitle">true</item>
<!-- 是否允许背景变暗 -->
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
代码的注释比较清晰,就不做过多说明了,有疑问的朋友欢迎在评论区留言。
搞定,收工。
希望本文可以帮助到您,也希望各位不吝赐教,提出您在使用中的宝贵意见,谢谢。
猜你喜欢
- 2025-01-26 Qt——常用控件(qtcreator控件)
- 2025-01-26 Flet 布局控件:ft.Page(页面),是根容器,是控件的容器View
- 2025-01-26 33个非常实用的JavaScript一行代码,建议收藏
- 2025-01-26 XtraReport控件VS微软RDLC报表,谁更胜一筹?
- 2025-01-26 Google官方梳理,Android 多返回栈技术详解
- 2025-01-26 Python入坑系列-pyside6桌面开发之QmainWindow自定义标题栏
- 2025-01-26 「3D建模」3Dmax快捷键大全(3dmax建模常用快捷键)
- 2025-01-26 第3天 | 28天学会PyQt5,基本窗口
- 2025-01-26 有办法了!批量删除多个Word页眉页脚
- 2025-01-26 鸿蒙开发:实现popup弹窗(鸿蒙系统没弹幕)
你 发表评论:
欢迎- 最近发表
-
- 解决Win10打开软件提示“服务器没有及时响应或控制请求”
- 用友UAP解开非结构化大数据处理与分析的密码
- Windows 25H2 修复底层崩溃(windows修复环境)
- 开源技巧:使用Docker实现交互式任务
- Win11 任意版本 直接安装 Android 应用 教程完整版
- Windows Terminal已成为Windows 11操作系统的默认终端
- 那些好莱坞电影中炫酷的特效 原来是这么拍的
- Windows 10 Build 21327.1010发布:测试服务管道更新
- Made in China: The story behind the label
- PowerShell登录远程Linux系统(powershell开启远程桌面)
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- googlecloud (64)
- flutterrun (59)
- 系统设计图 (58)
- powershellfor (73)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- qcombobox样式表 (68)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)