AlertDialog 源码解析一
来源:互联网 发布:mac 虚拟机装office 编辑:程序博客网 时间:2024/06/07 19:16
概要:
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); }
阅读全文
0 0
- AlertDialog 源码解析一
- AlertDialog源码解析
- AlertDialog源码解析之一
- android源码解析--AlertDialog及AlertDialog.Builder
- Android源码解析--AlertDialog及AlertDialog.Builder
- android源码解析--AlertDialog及AlertDialog.Builder
- AlertDialog解析
- 设计模式--[4]建造者模式和AlertDialog源码解析
- SaltStack源码解析一
- box2d源码解析 一
- TFS源码解析一
- bind源码解析(一)
- EventBus 源码解析(一)
- Lire源码解析一
- quartz源码解析(一)
- Volley源码解析(一)
- Picasso源码解析 一
- BroadcastReceiver源码解析(一)
- MongoDB配置
- 第十二周 项目(5)
- 在center os6.5上安装最新火狐,总是报错
- 百度地图动态添加marker的图片显示问题
- 解决Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com
- AlertDialog 源码解析一
- Null value was assigned to a property of primitive type setter
- Java中多态性的实现
- 用pandas里的groupby函数实现把一个大文件按某一列的类型分成多个文件
- 获取excel中每行的图片
- iOS不同屏幕适配字体大小
- js继承方式
- 【CCF】201509_3 模板生成器
- cout的格式化控制