AlertDialog源码分析
来源:互联网 发布:手机手势软件 编辑:程序博客网 时间:2024/05/22 08:10
构造方法
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()方法,我们进入看看:
@Overrideprotected 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相应的方法来设置本身的值
@Overridepublic 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,并支持单选和多选方式
- AlertDialog源码分析
- AlertDialog源码分析
- Android源码中的AlertDialog分析
- [ApiDemos] AlertDialog 使用和源码分析
- AlertDialog源码分析(建造者模式)
- AlertDialog分析
- 通过源码分析,修改AlertDialog按钮的颜色
- Android进阶系列之源码分析AlertDialog建造者模式
- AlertDialog 源码分析及Bulider 模式打造万能的dialog
- Builder设计模式和AlertDialog的源码分析
- 设计模式之----建造者模式(AlertDialog源码分析)
- AlertDialog源码解析
- AlertDialog源码解析之一
- AlertDialog 源码布局调整
- AlertDialog 源码解析一
- android源码解析--AlertDialog及AlertDialog.Builder
- Android源码解析--AlertDialog及AlertDialog.Builder
- android源码解析--AlertDialog及AlertDialog.Builder
- 使用Azure和OpenStack的云编排 - 未开发的混合云
- android webview Cannot call determinedVisibility() - never saw a connection for the pid:
- 安装PL/SQL及其instantclient的使用
- Shell主要逻辑源码级分析 (2)——SHELL作业控制
- 使用 /sys 文件系统访问 Linux 内核
- AlertDialog源码分析
- 14. Longest Common Prefix
- 在Windows7 系统上部署网关代理服务器
- MySQL快速入门
- 使用终端命令行将本地项目上传到Github
- SQL2008安装教程
- Scala构建工具(SBT)教程
- iOS库 .a与.framework区别
- Java break跳出多层循环