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();    }};
  1. 当三种按钮的其中一种被点击时,调用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为空,则隐藏标题栏
    1. 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);}
  1. 通过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;}

总结

  1. 假如只需要显示一行文字,可通过调用setMessage()设置需要显示的文字即可
  2. 可自定义title,通过setCustomTitle()方法设置
  3. 可自定义内容view,通过setView方法设置
  4. AlertDialog提供了三种可用按钮,可通过setPositiveButton、setNegativeButton和setNegativeButton设置显示和监听点击
  5. AlertDialog提供了内置的ListView,并支持单选和多选方式
0 0