AlertDialog 源码解析一
2017-11-30 11:53
106 查看
概要:
AlertDialog,平常用的很多,今天走了一遍内部实现,记录一下。
解析:
一AlertDialog的常用调用:
这是一个典型的Builder的构建者模式,Builder作为AlertDialog的内部类,专门用于构建AlertDialog对象。
Builder的链式调用,能够很好的简化代码。
AlertDialog与Builder的内部实现:
1,创建AlertDialog.Builder的时候,会创建AlertController.AlertParams对象P,P里面封装了所有的Dialog
的属性。
2,我们在调用Builder的setTitle,setMessage的时候,其实就是在将方法的参数值赋值给AlertParams P;
3,在Builder的create方法里面,会构建AlertDialog对像dialog。其中P.apply(dialog.mAlert);就是将P的属性
全部设置到Dialog的属性变量mAlert中:
5,这里会调用dispatchOnCreate(null),最终会回调AlertDialog的onCreate方法。
7,最后通过mWindowManager.addView(mDecorView, l);加载到屏幕上。
注:
1,由上分析可知,我们如果想要自定义Dialog,继承AlertDialog,重新onCreate方法(给个建议)。
AlertDialog,平常用的很多,今天走了一遍内部实现,记录一下。
解析:
一AlertDialog的常用调用:
new AlertDialog.Builder(mContext) .setTitle("title") .setMessage("message") .create() .show();
这是一个典型的Builder的构建者模式,Builder作为AlertDialog的内部类,专门用于构建AlertDialog对象。
Builder的链式调用,能够很好的简化代码。
AlertDialog与Builder的内部实现:
public class AlertDialog extends Dialog implements DialogInterface { private AlertController mAlert; AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) { super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0, createContextThemeWrapper); mWindow.alwaysReadCloseOnTouchAttr(); mAlert = AlertController.create(getContext(), this, getWindow()); } @Override public void setTitle(CharSequence title) { super.setTitle(title); mAlert.setTitle(title); } public void setMessage(CharSequence message) { mAlert.setMessage(message); } public static class Builder { private final AlertController.AlertParams P; public Builder(Context context, int themeResId) { P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDialogTheme(context, themeResId))); } public Builder setTitle(CharSequence title) { P.mTitle = title; return this; } public Builder setMessage(@StringRes int messageId) { P.mMessage = P.mContext.getText(messageId); return this; } public AlertDialog create() { // Context has already been wrapped with the appropriate theme. final AlertDialog dialog = new AlertDialog(P.mContext, 0, false); P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); dialog.setOnDismissListener(P.mOnDismissListener); if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; } public AlertDialog show() { final AlertDialog dialog = create(); dialog.show(); return dialog; } } }通过上面的代码分析:
1,创建AlertDialog.Builder的时候,会创建AlertController.AlertParams对象P,P里面封装了所有的Dialog
的属性。
2,我们在调用Builder的setTitle,setMessage的时候,其实就是在将方法的参数值赋值给AlertParams P;
3,在Builder的create方法里面,会构建AlertDialog对像dialog。其中P.apply(dialog.mAlert);就是将P的属性
全部设置到Dialog的属性变量mAlert中:
public void apply(AlertController dialog) { if (mCustomTitleView != null) { dialog.setCustomTitle(mCustomTitleView); } else { if (mTitle != null) { dialog.setTitle(mTitle); } if (mIcon != null) { dialog.setIcon(mIcon); } if (mIconId != 0) { dialog.setIcon(mIconId); } if (mIconAttrId != 0) { dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId)); } } if (mMessage != null) { dialog.setMessage(mMessage); } //省略了次要代码 }4,Builder的create方法,最后返回了AlertDialog对象dialog。所以最后show方法,是dialog.show();
public void show() { if (mShowing) { if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; if (!mCreated) { dispatchOnCreate(null); } else { // Fill the DecorView in on any configuration changes that // may have occured while it was removed from the WindowManager. final Configuration config = mContext.getResources().getConfiguration(); mWindow.getDecorView().dispatchConfigurationChanged(config); } onStart(); mDecor = mWindow.getDecorView(); if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { final ApplicationInfo info = mContext.getApplicationInfo(); mWindow.setDefaultIcon(info.icon); mWindow.setDefaultLogo(info.logo); mActionBar = new WindowDecorActionBar(this); } WindowManager.LayoutParams l = mWindow.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); nl.copyFrom(l); nl.softInputMode |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; l = nl; } mWindowManager.addView(mDecor, l); mShowing = true; sendShowMessage(); }
5,这里会调用dispatchOnCreate(null),最终会回调AlertDialog的onCreate方法。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAlert.installContent(); } //一下是AlertController类中方法。 public void installContent() { int contentView = selectContentView(); mWindow.setContentView(contentView); setupView(); } private int selectContentView() { if (mButtonPanelSideLayout == 0) { return mAlertDialogLayout; } if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) { return mButtonPanelSideLayout; } // TODO: use layout hint side for long messages/lists return mAlertDialogLayout; }6,mAlert.installContent,即是在初始化AlertDialog的控件。(即通过fingViewById,关联控件)
7,最后通过mWindowManager.addView(mDecorView, l);加载到屏幕上。
注:
1,由上分析可知,我们如果想要自定义Dialog,继承AlertDialog,重新onCreate方法(给个建议)。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initViews(getContext()); } private void initViews(Context context){ setContentView(R.layout.dialog_horizontal); tv_title = getWindow().findViewById(R.id.tv_title); tv_size = getWindow().findViewById(R.id.tv_size); progressBar = getWindow().findViewById(R.id.progress); WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.width = DensityUtil.dp2px(context.getApplicationContext(), 320); // lp.width = WindowManager.LayoutParams.MATCH_PARENT; lp.height = WindowManager.LayoutParams.WRAP_CONTENT; getWindow().setAttributes(lp); }2,其中mWindow是PhoneWindow。在AlertDialog的构造方法中生成。
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) { if (createContextThemeWrapper) { if (themeResId == ResourceId.ID_NULL) { final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); themeResId = outValue.resourceId; } mContext = new ContextThemeWrapper(context, themeResId); } else { mContext = context; } mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); final Window w = new PhoneWindow(mContext);// mWindow = w; w.setCallback(this); w.setOnWindowDismissedCallback(this); w.setOnWindowSwipeDismissedCallback(() -> { if (mCancelable) { cancel(); } }); w.setWindowManager(mWindowManager, null, null); w.setGravity(Gravity.CENTER); mListenersHandler = new ListenersHandler(this); }
相关文章推荐
- Android源码解析--AlertDialog及AlertDialog.Builder
- Android源码解析:AlertDialog和WindowManager源码解析
- android源码解析--AlertDialog及AlertDialog.Builder
- android源码解析--AlertDialog及AlertDialog.Builder
- 源码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?
- Android源码解析之Dialog
- AlertDialog源码分析(建造者模式)
- Dialog创建流程源码解析
- dialog源码解析笔记
- Http请求解析Json与图片(AlertDialog)提示框
- 从源码带你理解AlertDialog.getButton为什么是null
- android源码解析(十九)-->Dialog加载绘制流程
- AlertDialog 源码分析及Bulider 模式打造万能的dialog
- Android中Dialog源码解析
- 完全自定义Android对话框AlertDialog的实现(系统源码)
- AlertDialog cancel() 销毁窗口流程解析
- 从源码看 AlertDialog.getButton(DialogInterface.BUTTON_POSITIVE) 为什么是 null
- Android开发,源码分析Dialog/AlertDialog的dismiss()和hide()的区别
- android源码解析--Dialog
- 【Android 源码解析】从源码角度深入理解Android中Dialog、PopUpWindow、Toast区别