AlertDialog 源码分析及Bulider 模式打造万能的dialog
来源:互联网 发布:python 自然语言解析 编辑:程序博客网 时间:2024/05/19 16:34
AlertDialog 源码分析及Bulider 模式打造万能的dialog
背景:不管我们在哪个项目中,都会用到dialog,会有不同的各种样式的dialog,Android自带的dialog采用的bulider模式,但是定制很差,往往项目中采用的dialog 都会需要一些动画,和弹出方式以及所用到的背景图片等等。这个时候我们往往采用自定义dialog,但是如果有很多不同样式的dialog,我们就需要创建好多个自定义的dialog类。这个时候就在想可不可以用一个dialog类,当然可以最简单的AlertDialog 就只有一个类,我们只需要传布局便可。
我们先看一下AlertDialog的源码,进行分析
查看源码是我们最好的学习方式
按住Ctrl右键点击查看AlertDialog的源码
public class AlertDialog extends AppCompatDialog implements DialogInterface
可以看到AlertDialog是继承AppCompatDialog类,我们来看一下这个类
可以看到AppCompatDialog extends Dialog 由此可见Android 的AlertDialog 也是一个自定义成的Dialog,至此我们的猜想是成立的,既然成立那就看一下他是怎么实现的继续看AppCompatDialog的构造函数,至于AppCompatDialog implements AppCompatCallback 这个接口我们先不考虑,官方的是这样注释的:Implemented this in order for AppCompat to be able to callback in certain situations. 有兴趣的可以自己去了解下。
private AppCompatDelegate mDelegate;public AppCompatDialog(Context context) { this(context, 0);}public AppCompatDialog(Context context, int theme) { super(context, getThemeResId(context, theme)); // This is a bit weird, but Dialog's are typically created and setup before being shown, // which means that we can't rely on onCreate() being called before a content view is set. // To workaround this, we call onCreate(null) in the ctor, and then again as usual in // onCreate(). getDelegate().onCreate(null); // Apply AppCompat's DayNight resources if needed getDelegate().applyDayNight();}protected AppCompatDialog(Context context, boolean cancelable, OnCancelListener cancelListener) { super(context, cancelable, cancelListener);}@Overrideprotected void onCreate(Bundle savedInstanceState) { getDelegate().installViewFactory(); super.onCreate(savedInstanceState); getDelegate().onCreate(savedInstanceState);}
可以看到和平常的自定义dialog没什么不同,但是多了一个AppCompatDelegate这个类:
AppCompatDelegate-
This class represents a delegate which you can use to extend AppCompat’s support to any
可以看到一段官方的注释,英语不好的话就在线翻译吧–|,这句话的意思是:
此类表示一个委托,可以使用它来将AppCompat的支持扩展。也就是说这是一个委托类
从源码中我们可以看到他是将许多方法都交给了这个委托类去处理,这个类有什么作用呢?如果有谁做过夜间模式的一定知道这个类AppCompatDelegate AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); 这个类有木有很熟悉,如果有不熟悉的可以去看这个链接,http://godcoder.me/2016/07/28/Android%20Material%20Design%E7%B3%BB%E5%88%97%E4%B9%8B%E5%A4%9C%E9%97%B4%E6%A8%A1%E5%BC%8F/
public ActionBar getSupportActionBar() { return getDelegate().getSupportActionBar();}@Overridepublic void setContentView(@LayoutRes int layoutResID) { getDelegate().setContentView(layoutResID);}@Overridepublic void setContentView(View view) { getDelegate().setContentView(view);}@Overridepublic void setContentView(View view, ViewGroup.LayoutParams params) { getDelegate().setContentView(view, params);}@Nullable@Overridepublic View findViewById(@IdRes int id) { return getDelegate().findViewById(id);}@Overridepublic void setTitle(CharSequence title) { super.setTitle(title); getDelegate().setTitle(title);}@Overridepublic void setTitle(int titleId) { super.setTitle(titleId); getDelegate().setTitle(getContext().getString(titleId));}@Overridepublic void addContentView(View view, ViewGroup.LayoutParams params) { getDelegate().addContentView(view, params);}@Overrideprotected void onStop() { super.onStop(); getDelegate().onStop();}
由此可以看出,源码写的非常全面,实现了夜间和日间模式的切换,这是一个非常好的思路。
AppCompatDialog 类分析完了,说白就是我们平常自定义的dialog,只是AppCompatDialog 还实现了夜间模式
我们继续返回AlertDialog 类,接下来我们主要看这一段代码 276行
public static class Builder { private final AlertController.AlertParams P; private final int mTheme; /** * Creates a builder for an alert dialog that uses the default alert * dialog theme. * <p> * The default alert dialog theme is defined by * {@link android.R.attr#alertDialogTheme} within the parent * {@code context}'s theme. * * @param context the parent context */ public Builder(@NonNull Context context) { this(context, resolveDialogTheme(context, 0)); } /** * Creates a builder for an alert dialog that uses an explicit theme * resource. * <p> * The specified theme resource ({@code themeResId}) is applied on top * of the parent {@code context}'s theme. It may be specified as a * style resource containing a fully-populated theme, such as * {@link R.style#Theme_AppCompat_Dialog}, to replace all * attributes in the parent {@code context}'s theme including primary * and accent colors. * <p>
很明显采用了Builder模式,我们来看一下是怎么样实现的:
看一下这个类 AlertController 从字面意思上可以看出是Alert 的控制器,我们挑一段代码查看:346行
public void setIcon(int resId) {
mIcon = null;
mIconId = resId;
if (mIconView != null) { if (resId != 0) { mIconView.setVisibility(View.VISIBLE); mIconView.setImageResource(mIconId); } else { mIconView.setVisibility(View.GONE); } }}
可以看出他是给icon赋值,也就是说这个控制器我们也可以写在Builder中,在Builder扩展赋值,也可以向源码一样写一个控制器public static class AlertParams 传参单独控制和扩展。
源码分析完毕,从源码我们可以学习到很多思想,很有益处
学到了技术,打磨我们的工具
下面我只写简单的实现方法
自定义一个Dialog
模式 布局 弹窗样式 弹出动画等逻辑和点击事件交给Builder去处理
public class CommentDialog extends Dialog {private View mView;private Activity context;private WindowManager.LayoutParams lp;//这里我将Builder自定义一个类,分开单独处理public CommentDialog(CommentBuilder builder) { super(builder.context); context = (Activity) builder.context; mView = builder.view;}public CommentDialog(CommentBuilder builder, int resStyle) { super(builder.context, resStyle); context = (Activity) builder.context; mView = builder.view;}@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(mView); setCanceledOnTouchOutside(false); Window window = getWindow(); window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); window.getDecorView().setPadding(0, 0, 0, 0); lp = window.getAttributes(); lp.gravity = Gravity.CENTER; //弹出位置 window.setAttributes(lp);}
}
Builder 类
public class CommentBuilder {public Context context;public View view;private int resStyle = -1;public boolean cancelTouchout;public CommentBuilder(Context context) { this.context = context;}/*** 布局** @param resView* @return*/public CommentBuilder view(int resView) { view = LayoutInflater.from(context).inflate(resView, null); return this;}/*** dialog样式** @param resStyle* @return*/public CommentBuilder style(int resStyle) { this.resStyle = resStyle; return this;}/*** 添加一个点击事件** @param viewRes* @param listener* @return*/public CommentBuilder addViewOnclick(int viewRes, View.OnClickListener listener) { view.findViewById(viewRes).setOnClickListener(listener); return this;}/*** 触摸dialog外部是否可以取消** @param val false 不可dismiss* @return*/public CommentBuilder cancelTouchout(boolean val) { cancelTouchout = val; return this;}public CommentDialog build() { if (resStyle != -1) { return new CommentDialog(this, resStyle); } else { return new CommentDialog(this); }}
}
如何使用呢
CommentBuilder builder = new CommentBuilder(CropperActivity.this); builder.view(R.layout.dialog_comment_upload_success_layout) .style(R.style.shareStyles) .setReview(R.id.dcus_tv, isReview) .addViewOnclick(R.id.ll_dialog_ok, CropperActivity.this); commentDialog = builder.build(); commentDialog.show();
注:对于不同样式的Dialog,我们只需要传不同的布局和样式,赋值和改变值还可以在Builder中扩展增加对应的方法;点击事件我们可以写在当前的Activity 和 Fragment onClick()中实现,若想添加多个点击事件 可以添加多个.addViewOnclick(R.id.XX, CropperActivity.this);我们还可以学习源码一样,写一个控制器进行控制,具体大家可以自己实现。
至此谢幕,技术的提升:千里之行,始于足下
- AlertDialog 源码分析及Bulider 模式打造万能的dialog
- Android打造万能的对话框Dialog(一)
- Android打造万能的对话框Dialog(二)
- Android打造万能的对话框Dialog(三)
- Builder设计模式和AlertDialog的源码分析
- Android开发,源码分析Dialog/AlertDialog的dismiss()和hide()的区别
- Dialog对话框分类及系统的 AlertDialog
- AlertDialog源码分析(建造者模式)
- Android之UI--打造万能自定义Dialog
- 万能的Dialog
- 打造万能的EmptyView
- AlertDialog.Builder和Dialog分析
- 设计模式之----建造者模式(AlertDialog源码分析)
- Android万能适配器CommonAdapter的源码分析
- AlertDialog源码分析
- AlertDialog源码分析
- Android进阶系列之源码分析AlertDialog建造者模式
- 打造RecyclerView的万能适配器
- 试图加载格式不正确的程序
- win10 uwp 自定义控件初始化
- hadoop集群启动脚本——解决启动hadoop集群时,效率低问题
- vue.js基础篇(持续更新)
- Android BroadcastReceiver 注意点
- AlertDialog 源码分析及Bulider 模式打造万能的dialog
- UDS简述
- Android单例设计模式
- win10 uwp 获得缩略图
- caffe 分类全记录
- web静态登录页面
- 日本名校申请
- hadoop集群停止脚本
- 央行数字货币研究所悄然挂牌 工作人员:已有一段时间