Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android源碼淺析--AlertController

android源碼淺析--AlertController

編輯:關於Android編程

在android源碼解析--AlertDialog及AlertDialog.Builder這篇文章中,講到在Builder中功能的實現主要是調用AlertController實現的,而該類是android內部類,在package com.android.internal.app包中,不能在Eclipse中通過ctrl鍵來跟蹤源碼,所以使用Source Insight軟件打開該軟件源碼,查看一下。   跟以前一樣,先看下AlertController類中的私有成員變量:     [java]   private final Context mContext;       private final DialogInterface mDialogInterface;       private final Window mWindow;              private CharSequence mTitle;          private CharSequence mMessage;          private ListView mListView;              private View mView;          private int mViewSpacingLeft;              private int mViewSpacingTop;              private int mViewSpacingRight;              private int mViewSpacingBottom;              private boolean mViewSpacingSpecified = false;              private Button mButtonPositive;          private CharSequence mButtonPositiveText;          private Message mButtonPositiveMessage;          private Button mButtonNegative;          private CharSequence mButtonNegativeText;          private Message mButtonNegativeMessage;          private Button mButtonNeutral;          private CharSequence mButtonNeutralText;          private Message mButtonNeutralMessage;          private ScrollView mScrollView;              private int mIconId = -1;              private Drawable mIcon;              private ImageView mIconView;              private TextView mTitleView;          private TextView mMessageView;          private View mCustomTitleView;              private boolean mForceInverseBackground;              private ListAdapter mAdapter;              private int mCheckedItem = -1;          private int mAlertDialogLayout;       private int mListLayout;       private int mMultiChoiceItemLayout;       private int mSingleChoiceItemLayout;       private int mListItemLayout;          private Handler mHandler;     mAlertDialogLayout:AlertDialog布局   mListLayout:List布局   mMultiChoiceItemLayout:多選布局   mSingleChoiceItemLayout:單選布局 mListItemLayout:listItem布局       接著下面是一個自定義的View OnClickListener事件,其目的把點擊對象的信息發送到對應的線程(UI線程):     [java]   View.OnClickListener mButtonHandler = new View.OnClickListener() {           public void onClick(View v) {               Message m = null;               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);               }               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();           }       };     前面獲取點擊傳遞的Message,發送到目標線程(UI線程),然後再發送一個Message,通知UI線程關閉此對話框。裡面使用到的ButtonHandler.MSG_DISMISS_DIALOG,就在下面代碼中定義(關於Message和Handler發送消息,請參看前面博文)。       [java]   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();               }           }       }     看一下邏輯的處理,如果傳進來的Message的信息是DialogInterface.BUTTON_POSITIVE、DialogInterface.BUTTON_NEGATIVE、DialogInterface.BUTTON_NEUTRAL響應其DialogInterface.OnClickListener中的OnClick事件。如果是MSG_DISMISS_DIALOG,就關閉其對話框窗口。     下面是一個判斷對話框單個Button是否應居中:     [java]   private static boolean shouldCenterSingleButton(Context context) {           TypedValue outValue = new TypedValue();           context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogCenterButtons,                   outValue, true);           return outValue.data != 0;       }     再往下是其構造函數:   [java]  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);          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();      }     初始化上面提到的私有變量(關於TypeArray的用法,參考:http://blog.csdn.net/aomandeshangxiao/article/details/7449973)。     下面的靜態方法是判斷View是否支持輸入:     [java]   static boolean canTextInput(View v) {           if (v.onCheckIsTextEditor()) {               return true;           }                      if (!(v instanceof ViewGroup)) {               return false;           }                      ViewGroup vg = (ViewGroup)v;           int i = vg.getChildCount();           while (i > 0) {               i--;               v = vg.getChildAt(i);               if (canTextInput(v)) {                   return true;               }           }                      return false;       }     是文本編輯控件就返回true,然後彈出軟鍵盤。     下面方法,插入內容:     [java]  public void installContent() {           /* We use a custom title so never request a window title */           //無標題模式           mWindow.requestFeature(Window.FEATURE_NO_TITLE);                      //如果視圖為空,或者不是可編輯控件,那麼就自動隱藏掉軟鍵盤           if (mView == null || !canTextInput(mView)) {               mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,                       WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);           }           //設置系統AlertDialog為視圖           mWindow.setContentView(mAlertDialogLayout);           setupView();       }     看一下其調用的setupView方法(384行):   [java]   private void setupView() {           LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);           setupContent(contentPanel);           boolean hasButtons = setupButtons();                      LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);           TypedArray a = mContext.obtainStyledAttributes(                   null, com.android.internal.R.styleable.AlertDialog, com.android.internal.R.attr.alertDialogStyle, 0);           boolean hasTitle = setupTitle(topPanel);                          View buttonPanel = mWindow.findViewById(R.id.buttonPanel);           if (!hasButtons) {               buttonPanel.setVisibility(View.GONE);               mWindow.setCloseOnTouchOutsideIfNotSet(true);           }              FrameLayout customPanel = null;           if (mView != null) {               customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);               FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);               custom.addView(mView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));               if (mViewSpacingSpecified) {                   custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,                           mViewSpacingBottom);               }               if (mListView != null) {                   ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;               }           } else {               mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE);           }                      /* Only display the divider if we have a title and a            * custom view or a message.           */           if (hasTitle) {               View divider = null;               if (mMessage != null || mView != null || mListView != null) {                   divider = mWindow.findViewById(R.id.titleDivider);               } else {                   divider = mWindow.findViewById(R.id.titleDividerTop);               }                  if (divider != null) {                   divider.setVisibility(View.VISIBLE);               }           }                      setBackground(topPanel, contentPanel, customPanel, hasButtons, a, hasTitle, buttonPanel);           a.recycle();       }     其中又相繼調用了setupContent()、setupTitle()、setBackground()、setupButtons()等方法,分別設置內容部分、標題部分、背景、底部等。 先看下setupContent()方法:     [java]   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);               }           }       }     設置對話框中間顯示view內容。     設置底部:     [java]   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(mButtonNeutral);               } else if (whichButtons == BIT_BUTTON_NEUTRAL) {                   centerButton(mButtonNeutral);               }           }                      return whichButtons != 0;       }     設置底部主要是對話框按鈕這一部分區域的設置,裡面調用了centerButton方法:   [java]   private void centerButton(Button button) {           LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();           params.gravity = Gravity.CENTER_HORIZONTAL;           params.weight = 0.5f;           button.setLayoutParams(params);           View leftSpacer = mWindow.findViewById(R.id.leftSpacer);           if (leftSpacer != null) {               leftSpacer.setVisibility(View.VISIBLE);           }           View rightSpacer = mWindow.findViewById(R.id.rightSpacer);           if (rightSpacer != null) {               rightSpacer.setVisibility(View.VISIBLE);           }       }     設置button水平居中。在setupButton代碼注釋裡面也說了:如果只有一個button,設置其居中並占據可用區域的一半。     再來看一下setupTitle():     [java]   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 {              final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);                            mIconView = (ImageView) mWindow.findViewById(R.id.icon);              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 if (mIconId == 0) {                                            /* 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                  View titleTemplate = mWindow.findViewById(R.id.title_template);                  titleTemplate.setVisibility(View.GONE);                  mIconView.setVisibility(View.GONE);                  topPanel.setVisibility(View.GONE);                  hasTitle = false;              }          }          return hasTitle;      }     首先,如果設置了自定義的頂部視圖,就是用自定義視圖,並隱藏標題模板視圖。否則使用默認視圖設置其頂部顯示標題文字,圖片的內容,如果沒有標題文字,也隱藏標題模板視圖。     後面是setBackground():     [java]  private void setBackground(LinearLayout topPanel, LinearLayout contentPanel,               View customPanel, boolean hasButtons, TypedArray a, boolean hasTitle,                View buttonPanel) {                      /* Get all the different background required */           int fullDark = a.getResourceId(                   R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);           int topDark = a.getResourceId(                   R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);           int centerDark = a.getResourceId(                   R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);           int bottomDark = a.getResourceId(                   R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);           int fullBright = a.getResourceId(                   R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);           int topBright = a.getResourceId(                   R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);           int centerBright = a.getResourceId(                   R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);           int bottomBright = a.getResourceId(                   R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);           int bottomMedium = a.getResourceId(                   R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);                      /*           * We now set the background of all of the sections of the alert.           * First collect together each section that is being displayed along           * with whether it is on a light or dark background, then run through           * them setting their backgrounds.  This is complicated because we need           * to correctly use the full, top, middle, and bottom graphics depending           * on how many views they are and where they appear.           */                      View[] views = new View[4];           boolean[] light = new boolean[4];           View lastView = null;           boolean lastLight = false;                      int pos = 0;           if (hasTitle) {               views[pos] = topPanel;               light[pos] = false;               pos++;           }                      /* The contentPanel displays either a custom text message or           * a ListView. If it's text we should use the dark background           * for ListView we should use the light background. If neither           * are there the contentPanel will be hidden so set it as null.           */           views[pos] = (contentPanel.getVisibility() == View.GONE)                    ? null : contentPanel;           light[pos] = mListView != null;           pos++;           if (customPanel != null) {               views[pos] = customPanel;               light[pos] = mForceInverseBackground;               pos++;           }           if (hasButtons) {               views[pos] = buttonPanel;               light[pos] = true;           }                      boolean setView = false;           for (pos=0; pos<views.length; pos++) {               View v = views[pos];               if (v == null) {                   continue;               }               if (lastView != null) {                   if (!setView) {                       lastView.setBackgroundResource(lastLight ? topBright : topDark);                   } else {                       lastView.setBackgroundResource(lastLight ? centerBright : centerDark);                   }                   setView = true;               }               lastView = v;               lastLight = light[pos];           }                      if (lastView != null) {               if (setView) {                                      /* ListViews will use the Bright background but buttons use                   * the Medium background.                   */                    lastView.setBackgroundResource(                           lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);               } else {                   lastView.setBackgroundResource(lastLight ? fullBright : fullDark);               }           }                      /* TODO: uncomment section below. The logic for this should be if            * it's a Contextual menu being displayed AND only a Cancel button            * is shown then do this.           */   //        if (hasButtons && (mListView != null)) {                              /* Yet another *special* case. If there is a ListView with buttons               * don't put the buttons on the bottom but instead put them in the               * footer of the ListView this will allow more items to be               * displayed.               */                              /*              contentPanel.setBackgroundResource(bottomBright);              buttonPanel.setBackgroundResource(centerMedium);              ViewGroup parent = (ViewGroup) mWindow.findViewById(R.id.parentPanel);              parent.removeView(buttonPanel);              AbsListView.LayoutParams params = new AbsListView.LayoutParams(                      AbsListView.LayoutParams.MATCH_PARENT,                       AbsListView.LayoutParams.MATCH_PARENT);              buttonPanel.setLayoutParams(params);              mListView.addFooterView(buttonPanel);              */   //        }                      if ((mListView != null) && (mAdapter != null)) {               mListView.setAdapter(mAdapter);               if (mCheckedItem > -1) {                   mListView.setItemChecked(mCheckedItem, true);                   mListView.setSelection(mCheckedItem);               }           }       }     首先是獲取不同的背景需求,然後去設置對話框不同部分的背景色,首先使用下面代碼收集起來各個部分的背景情況(或明或暗)然後根據不同視圖的顯示設置其頂部、中部、底部的背景。   [java]   View[] views = new View[4];           boolean[] light = new boolean[4];           View lastView = null;           boolean lastLight = false;                      int pos = 0;           if (hasTitle) {               views[pos] = topPanel;               light[pos] = false;               pos++;           }     如果其內容視圖顯示一個自定義文本或者一個ListView,文本應設置為深色背景,而ListView應設置為淺色背景,如沒有內容視圖,則設置其背景為null。   [java]   views[pos] = (contentPanel.getVisibility() == View.GONE)                    ? null : contentPanel;           light[pos] = mListView != null;           pos++;           if (customPanel != null) {               views[pos] = customPanel;               light[pos] = mForceInverseBackground;               pos++;           }           if (hasButtons) {               views[pos] = buttonPanel;               light[pos] = true;           }                      boolean setView = false;           for (pos=0; pos<views.length; pos++) {               View v = views[pos];               if (v == null) {                   continue;               }               if (lastView != null) {                   if (!setView) {                       lastView.setBackgroundResource(lastLight ? topBright : topDark);                   } else {                       lastView.setBackgroundResource(lastLight ? centerBright : centerDark);                   }                   setView = true;               }               lastView = v;               lastLight = light[pos];           }                      if (lastView != null) {               if (setView) {                                      /* ListViews will use the Bright background but buttons use                   * the Medium background. Listview應明亮些,button應該偏中色背景                   */                    lastView.setBackgroundResource(                           lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);               } else {                   lastView.setBackgroundResource(lastLight ? fullBright : fullDark);               }           }       再回到247行,看一些其他設置,設置標題:     [java]   public void setTitle(CharSequence title) {           mTitle = title;           if (mTitleView != null) {               mTitleView.setText(title);           }       }     設置自定義標題:   [java]  /**      * @see AlertDialog.Builder#setCustomTitle(View)      */      public void setCustomTitle(View customTitleView) {          mCustomTitleView = customTitleView;      }     設置顯示信息:   [java]   public void setMessage(CharSequence message) {        mMessage = message;        if (mMessageView != null) {            mMessageView.setText(message);        }    }     設置Dialog自定義視圖:   [java]   /**   * Set the view to display in the dialog.   */   public void setView(View view) {       mView = view;       mViewSpacingSpecified = false;   }       [java]   /**    * Set the view to display in the dialog along with the spacing around that view    */    public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,            int viewSpacingBottom) {        mView = view;        mViewSpacingSpecified = true;        mViewSpacingLeft = viewSpacingLeft;        mViewSpacingTop = viewSpacingTop;        mViewSpacingRight = viewSpacingRight;        mViewSpacingBottom = viewSpacingBottom;    }   這個方法可以設置視圖到上下左右的間距。     設置按鈕和其點擊後傳送的消息內容:     [java]  /**       * Sets a click listener or a message to be sent when the button is clicked.       * You only need to pass one of {@code listener} or {@code msg}.       *        * @param whichButton Which button, can be one of       *            {@link DialogInterface#BUTTON_POSITIVE},       *            {@link DialogInterface#BUTTON_NEGATIVE}, or       *            {@link DialogInterface#BUTTON_NEUTRAL}       * @param text The text to display in positive button.       * @param listener The {@link DialogInterface.OnClickListener} to use.       * @param msg The {@link Message} to be sent when clicked.       */       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");           }       }     設置對話框圖標:   [java]  /**    * Set resId to 0 if you don't want an icon.    * @param resId the resourceId of the drawable to use as the icon or 0    * if you don't want an icon.    */    public void setIcon(int resId) {        mIconId = resId;        if (mIconView != null) {            if (resId > 0) {                mIconView.setImageResource(mIconId);            } else if (resId == 0) {                mIconView.setVisibility(View.GONE);            }        }    }        public void setIcon(Drawable icon) {        mIcon = icon;        if ((mIconView != null) && (mIcon != null)) {            mIconView.setImageDrawable(icon);        }    }       設置對話框後面的窗體是否能夠獲得焦點(能不能響應用戶操作觸發的事件): [java]  public void setInverseBackgroundForced(boolean forceInverseBackground) {           mForceInverseBackground = forceInverseBackground;       }     獲取對話框提供的ListView: [java]  public ListView getListView() {           return mListView;       }     獲取按鈕: [java]  public Button getButton(int whichButton) {           switch (whichButton) {               case DialogInterface.BUTTON_POSITIVE:                   return mButtonPositive;               case DialogInterface.BUTTON_NEGATIVE:                   return mButtonNegative;               case DialogInterface.BUTTON_NEUTRAL:                   return mButtonNeutral;               default:                   return null;           }       }     按下或者抬起事件: [java]  @SuppressWarnings({"UnusedDeclaration"})       public boolean onKeyDown(int keyCode, KeyEvent event) {           return mScrollView != null && mScrollView.executeKeyEvent(event);       }          @SuppressWarnings({"UnusedDeclaration"})       public boolean onKeyUp(int keyCode, KeyEvent event) {           return mScrollView != null && mScrollView.executeKeyEvent(event);       }   下面定義了一個靜態內部類:RecycleListView(此listView Measure狀態下回收視圖) [java]   public static class RecycleListView extends ListView {           boolean mRecycleOnMeasure = true;              public RecycleListView(Context context) {               super(context);           }              public RecycleListView(Context context, AttributeSet attrs) {               super(context, attrs);           }              public RecycleListView(Context context, AttributeSet attrs, int defStyle) {               super(context, attrs, defStyle);           }              @Override           protected boolean recycleOnMeasure() {               return mRecycleOnMeasure;           }       }     還剩下最後一個靜態內部類:AlertParams [java]   public static class AlertParams {           public final Context mContext;           public final LayoutInflater mInflater;                      public int mIconId = 0;           public Drawable mIcon;           public CharSequence mTitle;           public View mCustomTitleView;           public CharSequence mMessage;           public CharSequence mPositiveButtonText;           public DialogInterface.OnClickListener mPositiveButtonListener;           public CharSequence mNegativeButtonText;           public DialogInterface.OnClickListener mNegativeButtonListener;           public CharSequence mNeutralButtonText;           public DialogInterface.OnClickListener mNeutralButtonListener;           public boolean mCancelable;           public DialogInterface.OnCancelListener mOnCancelListener;           public DialogInterface.OnKeyListener mOnKeyListener;           public CharSequence[] mItems;           public ListAdapter mAdapter;           public DialogInterface.OnClickListener mOnClickListener;           public View mView;           public int mViewSpacingLeft;           public int mViewSpacingTop;           public int mViewSpacingRight;           public int mViewSpacingBottom;           public boolean mViewSpacingSpecified = false;           public boolean[] mCheckedItems;           public boolean mIsMultiChoice;           public boolean mIsSingleChoice;           public int mCheckedItem = -1;           public DialogInterface.OnMultiChoiceClickListener mOnCheckboxClickListener;           public Cursor mCursor;           public String mLabelColumn;           public String mIsCheckedColumn;           public boolean mForceInverseBackground;           public AdapterView.OnItemSelectedListener mOnItemSelectedListener;           public OnPrepareListViewListener mOnPrepareListViewListener;           public boolean mRecycleOnMeasure = true;              /**           * Interface definition for a callback to be invoked before the ListView           * will be bound to an adapter.           */           public interface OnPrepareListViewListener {                              /**               * Called before the ListView is bound to an adapter.               * @param listView The ListView that will be shown in the dialog.               */               void onPrepareListView(ListView listView);           }                      public AlertParams(Context context) {               mContext = context;               mCancelable = true;               mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);           }                  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 (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);                   }               }                              /*              dialog.setCancelable(mCancelable);              dialog.setOnCancelListener(mOnCancelListener);              if (mOnKeyListener != null) {                  dialog.setOnKeyListener(mOnKeyListener);              }              */           }                      private void createListView(final AlertController dialog) {               final RecycleListView listView = (RecycleListView)                       mInflater.inflate(dialog.mListLayout, null);               ListAdapter adapter;                              if (mIsMultiChoice) {                   if (mCursor == null) {                       adapter = new ArrayAdapter<CharSequence>(                               mContext, dialog.mMultiChoiceItemLayout, R.id.text1, mItems) {                           @Override                           public View getView(int position, View convertView, ViewGroup parent) {                               View view = super.getView(position, convertView, parent);                               if (mCheckedItems != null) {                                   boolean isItemChecked = mCheckedItems[position];                                   if (isItemChecked) {                                       listView.setItemChecked(position, true);                                   }                               }                               return view;                           }                       };                   } else {                       adapter = new CursorAdapter(mContext, mCursor, false) {                           private final int mLabelIndex;                           private final int mIsCheckedIndex;                              {                               final Cursor cursor = getCursor();                               mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);                               mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);                           }                              @Override                           public void bindView(View view, Context context, Cursor cursor) {                               CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);                               text.setText(cursor.getString(mLabelIndex));                               listView.setItemChecked(cursor.getPosition(),                                       cursor.getInt(mIsCheckedIndex) == 1);                           }                                  @Override                           public View newView(Context context, Cursor cursor, ViewGroup parent) {                               return mInflater.inflate(dialog.mMultiChoiceItemLayout,                                       parent, false);                           }                                                  };                   }               } else {                   int layout = mIsSingleChoice                            ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;                   if (mCursor == null) {                       adapter = (mAdapter != null) ? mAdapter                               : new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems);                   } else {                       adapter = new SimpleCursorAdapter(mContext, layout,                                mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});                   }               }                              if (mOnPrepareListViewListener != null) {                   mOnPrepareListViewListener.onPrepareListView(listView);               }                              /* Don't directly set the adapter on the ListView as we might               * want to add a footer to the ListView later.               */               dialog.mAdapter = adapter;               dialog.mCheckedItem = mCheckedItem;                              if (mOnClickListener != null) {                   listView.setOnItemClickListener(new OnItemClickListener() {                       public void onItemClick(AdapterView parent, View v, int position, long id) {                           mOnClickListener.onClick(dialog.mDialogInterface, position);                           if (!mIsSingleChoice) {                               dialog.mDialogInterface.dismiss();                           }                       }                   });               } else if (mOnCheckboxClickListener != null) {                   listView.setOnItemClickListener(new OnItemClickListener() {                       public void onItemClick(AdapterView parent, View v, int position, long id) {                           if (mCheckedItems != null) {                               mCheckedItems[position] = listView.isItemChecked(position);                           }                           mOnCheckboxClickListener.onClick(                                   dialog.mDialogInterface, position, listView.isItemChecked(position));                       }                   });               }                              // Attach a given OnItemSelectedListener to the ListView               if (mOnItemSelectedListener != null) {                   listView.setOnItemSelectedListener(mOnItemSelectedListener);               }                              if (mIsSingleChoice) {                   listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);               } else if (mIsMultiChoice) {                   listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);               }               listView.mRecycleOnMeasure = mRecycleOnMeasure;               dialog.mListView = listView;           }       }   絕大多數參數都比較簡單,從字面意思就可以看明白,挑選幾個參數簡單說明一下:   mWindow:窗體類   mListView:可以對外提供一個ListView   mViewSpacingLeft:設置視圖左邊間隔   mViewSpacingSpecified:視圖是否是指定間距(默認為false)   mCheckedItems:bool值,多選框是否被選中   mIsMultiChoice:是否是多選       可以簡單的認為AlertParams類為AlertController的工具類,看下其裡面的兩個方法,第一個apply:     [java]  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 (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);                   }               }                              /*              dialog.setCancelable(mCancelable);              dialog.setOnCancelListener(mOnCancelListener);              if (mOnKeyListener != null) {                  dialog.setOnKeyListener(mOnKeyListener);              }              */           }     為Dialog設置各種屬性,在AlertDialog.Builder的create()方法中調用了該方法。     為Dialog創建一個listView:     [java]  private void createListView(final AlertController dialog) {               final RecycleListView listView = (RecycleListView)                       mInflater.inflate(dialog.mListLayout, null);               ListAdapter adapter;               //是否是多選               if (mIsMultiChoice) {             //是否是從數據庫中取出的值                   if (mCursor == null) {                       adapter = new ArrayAdapter<CharSequence>(                               mContext, dialog.mMultiChoiceItemLayout, R.id.text1, mItems) {                           @Override                           public View getView(int position, View convertView, ViewGroup parent) {                               View view = super.getView(position, convertView, parent);                               if (mCheckedItems != null) {                                   boolean isItemChecked = mCheckedItems[position];                                   if (isItemChecked) {                                       listView.setItemChecked(position, true);                                   }                               }                               return view;                           }                       };                   } else {                       adapter = new CursorAdapter(mContext, mCursor, false) {                           private final int mLabelIndex;                           private final int mIsCheckedIndex;                              {                               final Cursor cursor = getCursor();                               mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);                               mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);                           }                              @Override                           public void bindView(View view, Context context, Cursor cursor) {                               CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);                               text.setText(cursor.getString(mLabelIndex));                               listView.setItemChecked(cursor.getPosition(),                                       cursor.getInt(mIsCheckedIndex) == 1);                           }                                  @Override                           public View newView(Context context, Cursor cursor, ViewGroup parent) {                               return mInflater.inflate(dialog.mMultiChoiceItemLayout,                                       parent, false);                           }                                                  };                   }               } else {           //如果是單選或者普通的listview                   int layout = mIsSingleChoice                            ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;                   if (mCursor == null) {                       adapter = (mAdapter != null) ? mAdapter                               : new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems);                   } else {                       adapter = new SimpleCursorAdapter(mContext, layout,                                mCursor, new String[]{mLabelColumn}, new int[]{R.id.text1});                   }               }                              if (mOnPrepareListViewListener != null) {                   mOnPrepareListViewListener.onPrepareListView(listView);               }                              /* Don't directly set the adapter on the ListView as we might               * want to add a footer to the ListView later.            * 不要直接為listView設置adapter,因為一會可能需要為listView設置頁腳               */               dialog.mAdapter = adapter;               dialog.mCheckedItem = mCheckedItem;                           //設置監聽               if (mOnClickListener != null) {                   listView.setOnItemClickListener(new OnItemClickListener() {                       public void onItemClick(AdapterView parent, View v, int position, long id) {                           mOnClickListener.onClick(dialog.mDialogInterface, position);                           if (!mIsSingleChoice) {                               dialog.mDialogInterface.dismiss();                           }                       }                   });               } else if (mOnCheckboxClickListener != null) { //多選監聽                   listView.setOnItemClickListener(new OnItemClickListener() {                       public void onItemClick(AdapterView parent, View v, int position, long id) {                           if (mCheckedItems != null) {                               mCheckedItems[position] = listView.isItemChecked(position);                           }                           mOnCheckboxClickListener.onClick(                                   dialog.mDialogInterface, position, listView.isItemChecked(position));                       }                   });               }                              // Attach a given OnItemSelectedListener to the ListView               if (mOnItemSelectedListener != null) {                   listView.setOnItemSelectedListener(mOnItemSelectedListener);               }                           //如有選擇項,選擇單選或者多選               if (mIsSingleChoice) {                   listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);               } else if (mIsMultiChoice) {                   listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);               }               listView.mRecycleOnMeasure = mRecycleOnMeasure;               dialog.mListView = listView;           }       }     這個方法邏輯注釋在代碼中,不詳細解釋了,都比較簡單。 看AlertController源碼,可以結合AlertDialog源碼看。因為在AlertDialog中的大部分功能實現是靠調用AlertController類來實現。    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved