点击查看优化版通用Dialog的封装
日常开发中或多或少都会使用到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();
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 : [email protected]
* 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>
代码的注释比较清晰,就不做过多说明了,有疑问的朋友欢迎在评论区留言。
搞定,收工。
希望本文可以帮助到您,也希望各位不吝赐教,提出您在使用中的宝贵意见,谢谢。
如果可以的话,也可以扫一扫下方的二维码请作者喝一杯奶茶哈
谢谢您的观看。
有问题可发送至:[email protected]
欢迎交流,共同进步。