构造方法
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
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());
}
AlertDialog的构造函数都是protected或者默认修饰的,这就说明我们无法直接创建AlertDialog的对象实例。其内部的主要实现是:创建一个AlertController对象,该类单纯听名字就可猜出它的大概作用:AlertDialog的控制器
AlertController
在AlertDialog的构造函数中创建了一个AlertController对象,这个类的作用是什么呢?我们从它的构造函数开始分析:
public AlertController(Context context, DialogInterface di, Window window) {
mContext = context;
mDialogInterface = di;
mWindow = window;
mHandler = new ButtonHandler(di);
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.AlertDialog,
com.android.internal.R.attr.alertDialogStyle, 0);
mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
com.android.internal.R.layout.alert_dialog);
mButtonPanelSideLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_buttonPanelSideLayout, 0);
mListLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_listLayout,
com.android.internal.R.layout.select_dialog);
mMultiChoiceItemLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_multiChoiceItemLayout,
com.android.internal.R.layout.select_dialog_multichoice);
mSingleChoiceItemLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout,
com.android.internal.R.layout.select_dialog_singlechoice);
mListItemLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_listItemLayout,
com.android.internal.R.layout.select_dialog_item);
a.recycle();
}
这里主要做了两个操作:
- 创建了一个ButtonHandler实例
- 初始化一些系统提供的默认样式
ButtonHandler
private static final class ButtonHandler extends Handler {
// Button clicks have Message.what as the BUTTON{1,2,3} constant
private static final int MSG_DISMISS_DIALOG = 1;
private WeakReference<DialogInterface> mDialog;
public ButtonHandler(DialogInterface dialog) {
mDialog = new WeakReference<DialogInterface>(dialog);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
break;
case MSG_DISMISS_DIALOG:
((DialogInterface) msg.obj).dismiss();
}
}
}
可以看到,它是继承与Handler类的。再来看下它的实例在哪里被使用:
1. 用于按钮被点击时,关闭dialog(其类型为MSG_DISMISS_DIALOG)
private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@Override
public void onClick(View v) {
final Message m;
if (v == mButtonPositive && mButtonPositiveMessage != null) {
m = Message.obtain(mButtonPositiveMessage);
} else if (v == mButtonNegative && mButtonNegativeMessage != null) {
m = Message.obtain(mButtonNegativeMessage);
} else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
m = Message.obtain(mButtonNeutralMessage);
} else {
m = null;
}
if (m != null) {
m.sendToTarget();
}
// Post a message so we dismiss after the above handlers are executed
mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
.sendToTarget();
}
};
- 当三种按钮的其中一种被点击时,调用DialogInterface.OnClickListener的onClick()函数
public void setButton(int whichButton, CharSequence text,
DialogInterface.OnClickListener listener, Message msg) {
if (msg == null && listener != null) {
msg = mHandler.obtainMessage(whichButton, listener);
}
switch (whichButton) {
case DialogInterface.BUTTON_POSITIVE:
mButtonPositiveText = text;
mButtonPositiveMessage = msg;
break;
case DialogInterface.BUTTON_NEGATIVE:
mButtonNegativeText = text;
mButtonNegativeMessage = msg;
break;
case DialogInterface.BUTTON_NEUTRAL:
mButtonNeutralText = text;
mButtonNeutralMessage = msg;
break;
default:
throw new IllegalArgumentException("Button does not exist");
}
}
Builder
通常我们使用AlertDialog时,是通过其内部类Builder来实例化的:
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this).create();
那create里边做了什么操作呢?
/**
* Creates an {@link AlertDialog} with the arguments supplied to this
* builder.
* <p>
* Calling this method does not display the dialog. If no additional
* processing is needed, {@link #show()} may be called instead to both
* create and display the dialog.
*/
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;
}
在其内部,调用了AlertDialog包含三个参数的构造方法,创建了一个实例,并调用了P.apply(dialog.mAlert)方法。那这里的p是什么?apply的作用又是什么?我们接着往下看:
private final AlertController.AlertParams P;
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
p是一个AlertController.AlertParams类的实例,其内部含有一系列与AlertDialog有关的变量,在Builder构造函数中进行了初始化
我们接着看它的apply()方法:
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);
}
if (mPositiveButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null);
}
if (mNegativeButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null);
}
if (mNeutralButtonText != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null);
}
if (mForceInverseBackground) {
dialog.setInverseBackgroundForced(true);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
/*
dialog.setCancelable(mCancelable);
dialog.setOnCancelListener(mOnCancelListener);
if (mOnKeyListener != null) {
dialog.setOnKeyListener(mOnKeyListener);
}
*/
}
该方法接收一个AlertController类型的参数,在其中设置AlertController的一些属性值
那AlertController的这些属性值是如何被运用到AlertDialog上的呢?
还记得上篇Dialog源码分析分析的show()方法吗?该方法内部调用了dispatchOnCreate(null)方法,而这个方法内部调用了onCreate()方法。AlertDialog继承于Dialog,其重写了Dialog的onCreate()方法,我们进入看看:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
该方法内部调用了AlertController的installContent()方法,我们再进去:
public void installContent() {
/* We use a custom title so never request a window title */
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
int contentView = selectContentView();
mWindow.setContentView(contentView);
setupView();
setupDecor();
}
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;
}
private void setupView() {
final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
final boolean hasButtons = setupButtons();
final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
final TypedArray a = mContext.obtainStyledAttributes(
null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
final boolean hasTitle = setupTitle(topPanel);
final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
if (!hasButtons) {
buttonPanel.setVisibility(View.GONE);
final View spacer = mWindow.findViewById(R.id.textSpacerNoButtons);
if (spacer != null) {
spacer.setVisibility(View.VISIBLE);
}
mWindow.setCloseOnTouchOutsideIfNotSet(true);
}
final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
final View customView;
if (mView != null) {
customView = mView;
} else if (mViewLayoutResId != 0) {
final LayoutInflater inflater = LayoutInflater.from(mContext);
customView = inflater.inflate(mViewLayoutResId, customPanel, false);
} else {
customView = null;
}
final boolean hasCustomView = customView != null;
if (!hasCustomView || !canTextInput(customView)) {
mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
if (hasCustomView) {
final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
if (mViewSpacingSpecified) {
custom.setPadding(
mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);
}
if (mListView != null) {
((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
}
} else {
customPanel.setVisibility(View.GONE);
}
// Only display the divider if we have a title and a custom view or a
// message.
if (hasTitle) {
final View divider;
if (mMessage != null || customView != null || mListView != null) {
divider = mWindow.findViewById(R.id.titleDivider);
} else {
divider = mWindow.findViewById(R.id.titleDividerTop);
}
if (divider != null) {
divider.setVisibility(View.VISIBLE);
}
}
setBackground(a, topPanel, contentPanel, customPanel, buttonPanel, hasTitle, hasCustomView,
hasButtons);
a.recycle();
}
这几个方法很长,但其主要的作用就是:通过AlertController中保存的属性值,设置AlertDialog显示的内容等。
下边就结合alert_dialog.xml重点分析下setupView()方法:
// alert_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="9dip"
android:paddingBottom="3dip"
android:paddingStart="3dip"
android:paddingEnd="1dip">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical">
<LinearLayout android:id="@+id/title_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="6dip"
android:layout_marginBottom="9dip"
android:layout_marginStart="10dip"
android:layout_marginEnd="10dip">
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="6dip"
android:paddingEnd="10dip"
android:src="@drawable/ic_dialog_info" />
<com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
style="?android:attr/textAppearanceLarge"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart" />
</LinearLayout>
<ImageView android:id="@+id/titleDivider"
android:layout_width="match_parent"
android:layout_height="1dip"
android:visibility="gone"
android:scaleType="fitXY"
android:gravity="fill_horizontal"
android:src="@android:drawable/divider_horizontal_dark" />
<!-- If the client uses a customTitle, it will be added here. -->
</LinearLayout>
<LinearLayout android:id="@+id/contentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ScrollView android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingBottom="12dip"
android:paddingStart="14dip"
android:paddingEnd="10dip"
android:overScrollMode="ifContentScrolls">
<TextView android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip" />
</ScrollView>
</LinearLayout>
<FrameLayout android:id="@+id/customPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<FrameLayout android:id="@+android:id/custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:paddingBottom="5dip" />
</FrameLayout>
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical" >
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingStart="2dip"
android:paddingEnd="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
<Button android:id="@+id/button1"
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
android:layout_weight="0.25"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
1.contentPanel
<LinearLayout android:id="@+id/contentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ScrollView android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingBottom="12dip"
android:paddingStart="14dip"
android:paddingEnd="10dip"
android:overScrollMode="ifContentScrolls">
<TextView android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dip" />
</ScrollView>
</LinearLayout>
final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
可以看到,contentPanel里边包含了一个id为scrollView的ScrollView,而ScrollView里边包含了一个id为message的TextView。进入setupContent:
private void setupContent(LinearLayout contentPanel) {
mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
mScrollView.setFocusable(false);
// Special case for users that only want to display a String
mMessageView = (TextView) mWindow.findViewById(R.id.message);
if (mMessageView == null) {
return;
}
if (mMessage != null) {
mMessageView.setText(mMessage);
} else {
mMessageView.setVisibility(View.GONE);
mScrollView.removeView(mMessageView);
if (mListView != null) {
contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
contentPanel.addView(mListView,
new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
contentPanel.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f));
} else {
contentPanel.setVisibility(View.GONE);
}
}
}
这里边有几种情况:
- 假如mMessage不为空,设置mMessageView
- 假如mMessage为空,且mListiew不为空,则移除scrollview并添加mListView进去
- 假如mMessage为空,且mListiew也为空,则将contentPanel隐藏
2. setupButton
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical" >
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingStart="2dip"
android:paddingEnd="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
<Button android:id="@+id/button1"
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
android:layout_weight="0.25"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
private boolean setupButtons() {
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
int whichButtons = 0;
mButtonPositive = (Button) mWindow.findViewById(R.id.button1);
mButtonPositive.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonPositiveText)) {
mButtonPositive.setVisibility(View.GONE);
} else {
mButtonPositive.setText(mButtonPositiveText);
mButtonPositive.setVisibility(View.VISIBLE);
whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
}
mButtonNegative = (Button) mWindow.findViewById(R.id.button2);
mButtonNegative.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonNegativeText)) {
mButtonNegative.setVisibility(View.GONE);
} else {
mButtonNegative.setText(mButtonNegativeText);
mButtonNegative.setVisibility(View.VISIBLE);
whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
}
mButtonNeutral = (Button) mWindow.findViewById(R.id.button3);
mButtonNeutral.setOnClickListener(mButtonHandler);
if (TextUtils.isEmpty(mButtonNeutralText)) {
mButtonNeutral.setVisibility(View.GONE);
} else {
mButtonNeutral.setText(mButtonNeutralText);
mButtonNeutral.setVisibility(View.VISIBLE);
whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
}
if (shouldCenterSingleButton(mContext)) {
/*
* If we only have 1 button it should be centered on the layout and
* expand to fill 50% of the available space.
*/
if (whichButtons == BIT_BUTTON_POSITIVE) {
centerButton(mButtonPositive);
} else if (whichButtons == BIT_BUTTON_NEGATIVE) {
centerButton(mButtonNegative);
} else if (whichButtons == BIT_BUTTON_NEUTRAL) {
centerButton(mButtonNeutral);
}
}
return whichButtons != 0;
}
通过mButtonPositiveText、mButtonNeutralText和mButtonNegativeText是否为空来控制显示相应的Button,并设置相应的点击事件
3. setupTitle
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical">
<LinearLayout android:id="@+id/title_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="6dip"
android:layout_marginBottom="9dip"
android:layout_marginStart="10dip"
android:layout_marginEnd="10dip">
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingTop="6dip"
android:paddingEnd="10dip"
android:src="@drawable/ic_dialog_info" />
<com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
style="?android:attr/textAppearanceLarge"
android:singleLine="true"
android:ellipsize="end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart" />
</LinearLayout>
<ImageView android:id="@+id/titleDivider"
android:layout_width="match_parent"
android:layout_height="1dip"
android:visibility="gone"
android:scaleType="fitXY"
android:gravity="fill_horizontal"
android:src="@android:drawable/divider_horizontal_dark" />
<!-- If the client uses a customTitle, it will be added here. -->
</LinearLayout>
final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
final TypedArray a = mContext.obtainStyledAttributes(
null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
final boolean hasTitle = setupTitle(topPanel);
private boolean setupTitle(LinearLayout topPanel) {
boolean hasTitle = true;
if (mCustomTitleView != null) {
// Add the custom title view directly to the topPanel layout
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
topPanel.addView(mCustomTitleView, 0, lp);
// Hide the title template
View titleTemplate = mWindow.findViewById(R.id.title_template);
titleTemplate.setVisibility(View.GONE);
} else {
mIconView = (ImageView) mWindow.findViewById(R.id.icon);
final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
if (hasTextTitle) {
// Display the title if a title is supplied, else hide it.
mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
mTitleView.setText(mTitle);
// Do this last so that if the user has supplied any icons we
// use them instead of the default ones. If the user has
// specified 0 then make it disappear.
if (mIconId != 0) {
mIconView.setImageResource(mIconId);
} else if (mIcon != null) {
mIconView.setImageDrawable(mIcon);
} else {
// Apply the padding from the icon to ensure the title is
// aligned correctly.
mTitleView.setPadding(mIconView.getPaddingLeft(),
mIconView.getPaddingTop(),
mIconView.getPaddingRight(),
mIconView.getPaddingBottom());
mIconView.setVisibility(View.GONE);
}
} else {
// Hide the title template
final View titleTemplate = mWindow.findViewById(R.id.title_template);
titleTemplate.setVisibility(View.GONE);
mIconView.setVisibility(View.GONE);
topPanel.setVisibility(View.GONE);
hasTitle = false;
}
}
return hasTitle;
}
- 假如mCustomTitleView(可通过setCustomTitle设置)不为空,则直接将该view设置给topPanel
- 假如mCustomTitleView为空,并且设置了mTitle,则通过AlertController中的属性设置相应的视图
- 假如mCustomTitleView为空,并且mTitle为空,则隐藏标题栏
- customPanel
<FrameLayout android:id="@+id/customPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<FrameLayout android:id="@+android:id/custom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:paddingBottom="5dip" />
</FrameLayout>
final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
final View customView;
if (mView != null) {
customView = mView;
} else if (mViewLayoutResId != 0) {
final LayoutInflater inflater = LayoutInflater.from(mContext);
customView = inflater.inflate(mViewLayoutResId, customPanel, false);
} else {
customView = null;
}
final boolean hasCustomView = customView != null;
if (!hasCustomView || !canTextInput(customView)) {
mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
if (hasCustomView) {
final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
if (mViewSpacingSpecified) {
custom.setPadding(
mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);
}
if (mListView != null) {
((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
}
} else {
customPanel.setVisibility(View.GONE);
}
自定义的视图主要添加在android:id=”@+android:id/custom”的FrameLayout中,假如mListView不为空,则隐藏该布局
5. divider
if (hasTitle) {
final View divider;
if (mMessage != null || customView != null || mListView != null) {
divider = mWindow.findViewById(R.id.titleDivider);
} else {
divider = mWindow.findViewById(R.id.titleDividerTop);
}
if (divider != null) {
divider.setVisibility(View.VISIBLE);
}
}
主要设置标题栏与内容栏的间隔线,假如mMessage、customView或者mListView不为空,则显示
6. 设置背景
setBackground(a, topPanel, contentPanel, customPanel, buttonPanel, hasTitle, hasCustomView,
hasButtons);
属性设置
我们可以通过两种方式设置AlertController中的属性值
1. 通过AlertDialog的实例
// 例子
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this).create();
dialog.setTitle("1111");
进入setTitle方法,我们可以看到内部是调用了AlertController相应的方法来设置本身的值
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
- 通过Builder的实例
// 例子
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("111");
进入setTitle方法,我们可以看到内部是是将p的属性值设置成相应的值。通过我们上边的分析,知道p会通过apply方法把自己变量的值赋予AlertController相应的变量,最终还是通过AlertController来改变属性
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
总结
- 假如只需要显示一行文字,可通过调用setMessage()设置需要显示的文字即可
- 可自定义title,通过setCustomTitle()方法设置
- 可自定义内容view,通过setView方法设置
- AlertDialog提供了三种可用按钮,可通过setPositiveButton、setNegativeButton和setNegativeButton设置显示和监听点击
- AlertDialog提供了内置的ListView,并支持单选和多选方式