由于業務要求,需要在彈出AlertDialog的時候,将其中的一個按鈕置為灰色,即禁用點選功能。下面是具體的實作方法,一個Demo
布局很簡單,一個按鈕,點選後彈出禁用按鈕的AlertDialog,就不放代碼了。
主要說一下有關禁用方面的話題
class MyOnClickListener implements OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
builder = new AlertDialog.Builder(context);
builder.setTitle("對話框");
builder.setMessage("顯示對話框,并将禁用按鈕");
builder.setPositiveButton("确定", null);
builder.setNegativeButton("取消", null);
dialog = builder.create();
// 必須要先顯示對話框,再從裡面擷取Button,否則得到的Button為null
// 可以把下面這行注釋掉實驗一下,将列印null的LOG
dialog.show();
Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
if(null==button){
Log.i("carter", "button is null");
}else{
button.setEnabled(false);
}
}
}
這裡面有個很重要的地方需要說明一下,如果想得到裡面的Button,單單執行dialog = builder.create();和button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);是不夠的,會傳回一個null的button,必須要先調用dialog.show();方法 後再擷取BUtton,具體的原因不是很清楚,可能得去看源代碼了
看了Jelly Bean的源碼,大概了解的實作的過程。下面簡單分析下:
1、調用AlertDialog.show()方法,實際上是調用Dialog.show()方法
2、在show()方法中,會判斷是否已經顯示,如果是則傳回;沒有顯示則執行dispatchOnCreate(null)方法
if (!mCreated) {
dispatchOnCreate(null);
}
3、在dispatchOnCreate()方法中會去執行onCreate()方法,而這個onCreate()方法是由AlertDialog類具體實作的。在方法的注釋中寫着“内部方法,把mcreated設定成合适的值,而不需要使用者調用super類中的onCreate方法”
// internal method to make sure mcreated is set properly without requiring
// users to call through to super in onCreate
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
4、在AlertDialog的onCreate()方法中,去調用mAlert.installContent()方法。mAlert是一個AlertController類,位于android.internal.app包中。installContent方法,我的了解就是通過AlertController去裝載需要顯示的内容。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
5、在AlertController的installContent()方法中,會去執行setupView()方法,去建立、設定需要顯示的元件
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);
}
mWindow.setContentView(mAlertDialogLayout);
setupView();
}
6、在setupView()方法中,會先去加載設定顯示的内容,比如提示的資訊什麼的,
LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
在setupContent()方法中,擷取了一個ScrollView,可以滾動顯示加載的内容。這裡跟Button無關,可以簡單看下,知道就行了。
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);
}
}
}
7、設定完這些要顯示的資訊後,就會繼續在setupView()方法中加載Button了,關鍵的地方終于來了。
boolean hasButtons = setupButtons();
8、在setupButtons()方法中,就會一個個的去生成這些Button,設定監聽器、顯示的内容等資訊。
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;
}
9、執行完上面這些,Content和Button就都被初始化完成了,是以也就驗證了為什麼在沒有調用show()方法之前,傳回的Button會是null的問題。