更多关于安卓源码分析文章,请看:Android源码分析专栏
最近工作需要,将AlertDialog的源码拷贝一份并替换为公司所要求的界面,这样就拥有了一个完全属于公司自己的弹窗。在这个过程中,也研究了AlertDialog的源码,觉得也有不少的收获,于是分享一下,如果可以帮助同行更好熟悉AlertDialog那就更wonderful了。以下为安卓版本为5.1。
首先必须明确一点,AlertDialog是Dialog的子类,他扩展了Dialog的功能,例如可以选择积极,消极,中性按钮,增加标题、消息等。
首先是构造方法。由于构造方法修饰符都是protected或者默认,所以我们在程序使用中不能直接new一个AlertDialog。而使用过AlertDialog的朋友一定知道要使用Builder类去构建一个AlertDialog。那构造方法会在哪里调用呢?是的,你们都能猜到是在Builder中,而Buidler和AlertDialog类是什么关系呢?后面会一一帮你们解释~~
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
/**
* Construct an AlertDialog that uses an explicit theme. The actual style
* that an AlertDialog uses is a private implementation, however you can
* here supply either the name of an attribute in the theme from which
* to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
* or one of the constants {@link #THEME_TRADITIONAL},
* {@link #THEME_HOLO_DARK}, or {@link #THEME_HOLO_LIGHT}.
*/
protected AlertDialog(Context context, int theme) {
this(context, theme, true);
}
AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, resolveDialogTheme(context, 0));
mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
构造方法主要就是传入上下文Context(一般就是弹窗所在的Activity)、Cancel监听器、样式(这个传入父类Dialog处理,默认为0,则使用系统指定的样式)、createContextThemeWrapper是传给父类Dialog的,这个涉及到Dialog中的ContextThemeWrapper(Context一个包装类),这里可以暂时不管。
可以看到这里new出了一个类:AlertController。这个类将是重点类,因为AlertDialog核心代码都在这个类中执行,可以看作其核心控制类。要知道这个类,首先先看下Builder,它是AlertDialog的内部类,作用就是去构建一个AlertDialog,客户端程序可以很方便地传入自己想要的多个参数去构建一个开发者需要的AlertDialog。
首先看下Builder的部分主要代码:
public static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
/**
* Constructor using a context for this builder and the {@link AlertDialog} it creates.
*/
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
/**
* Constructor using a context and theme for this builder and
* the {@link AlertDialog} it creates. The actual theme
* that an AlertDialog uses is a private implementation, however you can
* here supply either the name of an attribute in the theme from which
* to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
* or one of the constants
* {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL},
* {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or
* {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}.
*/
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
/**
* Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
* Applications should use this Context for obtaining LayoutInflaters for inflating views
* that will be used in the resulting dialogs, as it will cause views to be inflated with
* the correct theme.
*
* @return A Context for built Dialogs.
*/
public Context getContext() {
return P.mContext;
}
/**
* Set the title using the given resource id.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
/**
* Set the title displayed in the {@link Dialog}.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
/**
* Set the title using the custom view {@code customTitleView}. The
* methods {@link #setTitle(int)} and {@link #setIcon(int)} should be
* sufficient for most titles, but this is provided if the title needs
* more customization. Using this will replace the title and icon set
* via the other methods.
*
* @param customTitleView The custom view to use as the title.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
/**
* Set the message to display using the given resource id.
*
* @