在 Android 中,對話框有以下五種:
+ Dialog
+ AlertDialog
+ CharacterPickerDialog
+ DatePickerDialog
+ ProgressDialog
其中 Dialog 是所有對話框的基類。 AlertDialog 和 CharacterPickerDialog 是 Dialog 的直接派生類, DatePickerDialog 、 ProgressDialog 和 TimePickerDialog 是 Dialog 的間接派生類。 CharacterPickerDialog 的用處感覺不大,而且在 Android2.2 之前的版本似乎有 bug 。
下面文字中 “ 對話框 ” 的含義,包括 Dialog 自己及其所有的派生類。
+ 對話框必須在使用它的 Activity 中定義;
+ Activity 中有三個和對話框顯示有關的方法,即 showDialog() , dismissDialog() 和 removeDialog() 。其中 showDialog() 方法用於顯示一個對話框; dismissDialog() 使對話框消失,但仍然處於內存中,只是不顯示而已,如果再次調用 showDialog() 方法,則緩存在內容的對話框,會重新顯示,而不需要重新創建。 removeDialog() 使對話框消失,並從內存中將對話框清除,如果再次調用 showDialog() 方法來顯示它,則在顯示之前需要重新創建該對話框。相關函數的原型如下:
public final void showDialog (int id)
public final boolean showDialog (int id, Bundle args)
public final void dismissDialog (int id)
public final void removeDialog (int id)
其中第一個參數 id ,均爲對話框所對應的 ID 。
+ 在 Activity 中增加一個對話框的步驟大致如下:
- 在 Activity 中爲對話框定義唯一的標識符 (ID)
- 重寫 Activity 中的 onCreateDialog() 方法,並返回一個對話框實例
- 重寫 Activity 中的 onPrepareDialog() 方法。該方法不是必須重寫的,但可以在該方法中爲相關的對話框改變一些屬性設置
- 調用 showDialog() 方法,顯示該對話框
需要注意的是,在一個對話框的聲明週期內, onCreateDialog() 僅被調用一次,但 onPrepareDialog() 方法可以被多次調用。比如,第一次調用 showDialog() 方法顯示某個對話框時,會先觸發 onCreateDialog() 方法的執行,然後再觸發 onPrepareDialog() 方法的執行;如果將某個對話框 removeDialog() 後,再次用 showDialog() 顯示它是,也會先觸發 onCreateDialog() 方法的執行,然後再觸發 onPrepareDialog() 方法的執行;如果某個對話框被 dismissDialog() 在屏幕上消失後,在調用 showDialog() 方法來顯示它的話,則不會觸發 onCreateDialog() 方法的執行,但會觸發 onPrepareDialog() 方法的執行。正因爲如此,可以在該方法中爲相關的對話框 ( 同一個 ID) 改變一些屬性設置。
+ 在 Dialog 中也存在功能分別和 Activity 中的 showDialog() 和 dismissDialog() 方法一樣的方法,它們是 show() 和 dismiss() ,其原型如下:
public void show ()
public void dismiss ()
但沒有對應的 remove() 方法,理由很簡單, removeDialog() 方法調用後,對話框實例已經不存在了,所以此時在對話框中的 remove 方法已經沒有意義了。
1. 創建 Android Project ,修改其 main.xml ,使之如下:
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:gravity = "center_horizontal"
>
< Button
android:id = "@+id/show_button1"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "Dialog (1)"
/>
< Button
android:id = "@+id/show_button2"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "AlertDialog (2)"
/>
< Button
android:id = "@+id/show_button3"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "AlertDialog (3)"
/>
< Button
android:id = "@+id/show_button4"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "AlertDialog (4)"
/>
< Button
android:id = "@+id/show_button5"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "AlertDialog (5)"
/>
< Button
android:id = "@+id/show_button6"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "AlertDialog (6)"
/>
< Button
android:id = "@+id/show_button7"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "CharacterPickerDialog (7)"
/>
< Button
android:id = "@+id/show_button8"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "DatePickerDialog (8)"
/>
< Button
android:id = "@+id/show_button9"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "TimePickerDialog (9)"
/>
< Button
android:id = "@+id/show_button10"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "ProgressDialog (10)"
/>
< Button
android:id = "@+id/show_button11"
android:layout_width = "220px"
android:layout_height = "38px"
android:text = "Customized Dialog (11)"
/>
</ LinearLayout >
2. 創建一個 layout 文件: custom_dialog.xml ,使其內容如下:
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_height = "wrap_content"
android:layout_width = "wrap_content"
android:background = "#ffffffff"
android:orientation = "horizontal"
android:gravity = "center_horizontal"
android:id = "@+id/dialog" >
< TextView
android:layout_height = "wrap_content"
android:layout_width = "wrap_content"
android:id = "@+id/tvname"
android:text = " 姓名 : "
/>
< EditText
android:layout_height = "wrap_content"
android:layout_width = "wrap_content"
android:id = "@+id/etname"
android:minWidth = "140px"
/>
</ LinearLayout >
這個 layout 將用於自定義的對話框。
3. 修改 Activity 所對應的代碼,使之如下:
package com.pnf.gui;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.CharacterPickerDialog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TimePicker;
import android.widget.Toast;
public class ControlDialog extends Activity
implements
OnClickListener
{
// 聲明一個 Dialog 對象
private Dialog dialog = null ;
// 聲明 11 個 Button 對象 , 他們分別用於顯示 11 個不同的對話框
private Button show_button1 ;
private Button show_button2 ;
private Button show_button3 ;
private Button show_button4 ;
private Button show_button5 ;
private Button show_button6 ;
private Button show_button7 ;
private Button show_button8 ;
private Button show_button9 ;
private Button show_button10 ;
private Button show_button11 ;
// 給 11 個不同的對話框設定 ID
private static final int ID_DIALOG1 = 1;
private static final int ID_DIALOG2 = 2;
private static final int ID_DIALOG3 = 3;
private static final int ID_DIALOG4 = 4;
private static final int ID_DIALOG5 = 5;
private static final int ID_DIALOG6 = 6;
private static final int ID_DIALOG7 = 7;
private static final int ID_DIALOG8 = 8;
private static final int ID_DIALOG9 = 9;
private static final int ID_DIALOG10 = 10;
private static final int ID_DIALOG11 = 11;
// 用於保存 ID 爲 ID_DIALOG5 的對話框的狀態
private boolean id_dialog5 [] = { false , false };
// 用於保存 ID 爲 ID_DIALOG6 的對話框的狀態
private int id_dialog6 = 0;
// 定義一個 Handler 對象 , 用於更新 ProgressDialog(ID 爲 ID_DIALOG10) 中的進度條
// 相關做法可以參考 : 《 AndroidGUI06 : ProgressBar 常用技巧》
private Handler progressHandler = new Handler()
{
public void handleMessage(Message msg) // 重寫 handleMessage 方法
{
((ProgressDialog) dialog ).setProgress(msg. what * 10);
if (msg. what == 1000) dismissDialog( ID_DIALOG10 );
}
};
public void onCreate(Bundle savedInstanceState)
{
super .onCreate(savedInstanceState);
setContentView(R.layout. main );
// 獲取 11 按鈕對象 , 並分別爲他們設置 OnClickListener
show_button1 = (Button) this .findViewById(R.id. show_button1 );
show_button1 .setOnClickListener( this );
show_button2 = (Button) this .findViewById(R.id. show_button2 );
show_button2 .setOnClickListener( this );
show_button3 = (Button) this .findViewById(R.id. show_button3 );
show_button3 .setOnClickListener( this );
show_button4 = (Button) this .findViewById(R.id. show_button4 );
show_button4 .setOnClickListener( this );
show_button5 = (Button) this .findViewById(R.id. show_button5 );
show_button5 .setOnClickListener( this );
show_button6 = (Button) this .findViewById(R.id. show_button6 );
show_button6 .setOnClickListener( this );
show_button7 = (Button) this .findViewById(R.id. show_button7 );
show_button7 .setOnClickListener( this );
show_button8 = (Button) this .findViewById(R.id. show_button8 );
show_button8 .setOnClickListener( this );
show_button9 = (Button) this .findViewById(R.id. show_button9 );
show_button9 .setOnClickListener( this );
show_button10 = (Button) this .findViewById(R.id. show_button10 );
show_button10 .setOnClickListener( this );
show_button11 = (Button) this .findViewById(R.id. show_button11 );
show_button11 .setOnClickListener( this );
}
// 在 OnClick 方法中 , 調用 showDialog(int id, Bundle args) 顯示一個對話框時 ,
// showDialog 的兩個參數 , 會分別傳遞給 onCreateDialog
protected Dialog onCreateDialog( int id, Bundle args)
{
// 定義一個 AlertDialog.Builder 對象。創建 AlertDialog 時,都要用到這個
// AlertDialog.Builder 對象。自定義的對話框,本質上也是一個 AlertDialog ,
// 因此創建自定義對話框,也需要用到 AlertDialog.Builder
AlertDialog.Builder builder;
switch (id)
{
case ID_DIALOG1 : // 創建一個基本的對話框
dialog = new Dialog( this );
break ;
case ID_DIALOG2 : // 創建一個 AlertDialog , 有兩個按鈕
builder = new AlertDialog.Builder(ControlDialog. this );
builder.setTitle( "Prompt" );
builder.setMessage( "Are you sure to quit?" );
builder.setPositiveButton( "OK" , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
// 當 which=-1 時 ( 即 BUTTON_POSITIVE) , 說明是 positive 按鈕
// 當 which=-2 時 ( 即 BUTTON_NEGATIVE) , 說明是 negative 按鈕
Log.e ( "AlertDialog" , dialog.toString()+ " " + which);
// do something else
dialog.dismiss(); // 可以沒有這句
}
});
builder.setNegativeButton( "Cancel" , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
// 當 which=-1 時 ( 即 BUTTON_POSITIVE) , 說明是 positive 按鈕
// 當 which=-2 時 ( 即 BUTTON_NEGATIVE) , 說明是 negative 按鈕
Log.e ( "AlertDialog" , dialog.toString()+ " " + which);
// do something else
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
case ID_DIALOG3 : // 創建一個 AlertDialog , 有三個按鈕
builder = new AlertDialog.Builder(ControlDialog. this );
builder.setIcon(android.R.drawable. btn_star );
builder.setTitle( "Survey of Favorite Star" );
builder.setMessage( "Do you like Jet Lee?" );
builder.setPositiveButton( "Great!" , new DialogInterface.OnClickListener()
{ // 當 which=-1 時 ( 即 BUTTON_POSITIVE) , 說明是 positive 按鈕
// 當 which=-2 時 ( 即 BUTTON_NEGATIVE) , 說明是 negative 按鈕
// 當 which=-3 時 ( 即 BUTTON_NEUTRAL) , 說明是 neutral 按鈕
public void onClick(DialogInterface dialog, int which)
{
Toast.makeText (ControlDialog. this , "I love him..." , Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
builder.setNegativeButton( "Hate!" , new DialogInterface.OnClickListener()
{ // 當 which=-1 時 ( 即 BUTTON_POSITIVE) , 說明是 positive 按鈕
// 當 which=-2 時 ( 即 BUTTON_NEGATIVE) , 說明是 negative 按鈕
// 當 which=-3 時 ( 即 BUTTON_NEUTRAL) , 說明是 neutral 按鈕
public void onClick(DialogInterface dialog, int which)
{
Toast.makeText (ControlDialog. this , "I hate him..." , Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
builder.setNeutralButton( "OK!" , new DialogInterface.OnClickListener()
{ // 當 which=-1 時 ( 即 BUTTON_POSITIVE) , 說明是 positive 按鈕
// 當 which=-2 時 ( 即 BUTTON_NEGATIVE) , 說明是 negative 按鈕
// 當 which=-3 時 ( 即 BUTTON_NEUTRAL) , 說明是 neutral 按鈕
public void onClick(DialogInterface dialog, int which)
{
Toast.makeText (ControlDialog. this , "Let me think..." , Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
case ID_DIALOG4 : // 創建一個 AlertDialog , 有一個按鈕和一個輸入框
builder = new AlertDialog.Builder(ControlDialog. this );
builder.setIcon(android.R.drawable. ic_dialog_info );
builder.setTitle( "Please input something" );
final EditText edit = new EditText( this );
builder.setView(edit);
builder.setPositiveButton( "OK" , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Toast.makeText (ControlDialog. this , edit.getText().toString(), Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
case ID_DIALOG5 : // 創建一個 AlertDialog , 有一個按鈕和兩個 CheckBox
builder = new AlertDialog.Builder(ControlDialog. this );
builder.setIcon(android.R.drawable. ic_dialog_info );
builder.setTitle( "CheckBox in AlertDialog" );
builder.setMultiChoiceItems( new String[]{ "Item1" , "Item2" },
id_dialog5 , // 用 id_dialog5 數組記錄 CheckBox 的狀態
new DialogInterface.OnMultiChoiceClickListener()
{
public void onClick(DialogInterface dialog, int which, boolean isChecked)
{
switch (which)
{
case 0:
if (isChecked) id_dialog5 [0] = true ;
else id_dialog5 [0] = false ;
break ;
case 1:
if (isChecked) id_dialog5 [1] = true ;
else id_dialog5 [1] = false ;
break ;
}
}
});
builder.setPositiveButton( "OK" , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
String tmpstr = "" ;
if ( id_dialog5 [0]) tmpstr = "Item1 is checked" ;
else tmpstr = "Item1 is not checked." ;
tmpstr += "/n" ;
if ( id_dialog5 [1]) tmpstr += "Item2 is checked" ;
else tmpstr += "Item2 is not checked." ;
Toast.makeText (ControlDialog. this , tmpstr, Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
case ID_DIALOG6 : // 創建一個 AlertDialog ,有一個按鈕和兩個 RadioButton
builder = new AlertDialog.Builder(ControlDialog. this );
builder.setIcon(android.R.drawable. ic_dialog_info );
builder.setTitle( "RadioButton in AlertDialog" );
builder.setSingleChoiceItems( new String[]{ "Item1" , "Item2" },
id_dialog6 , // 用 id_dialog6 記錄那個 RadioButton 被選中
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
id_dialog6 = which;
}
});
builder.setPositiveButton( "OK" , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
String tmpstr = "" ;
if ( id_dialog6 == 0) tmpstr = "Item1 is selected" ;
else tmpstr = "Item2 is selected" ;
Toast.makeText (ControlDialog. this , tmpstr, Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
case ID_DIALOG7 : // 創建一個 CharacterPickerDialog
dialog = new CharacterPickerDialog( this , new View( this ), null , "0123" , false )
{
/* if we don't override these, pressing one of the buttons crashes */
@Override
public void onItemClick(AdapterView parent,
View view,
int position, long id)
{
Log.e ( "1" , "" + position + "/" + id);
}
@Override
public void onClick(View v)
{
Log.e ( "2" , ((Button)v).getText().toString());
dismiss();
}
};
break ;
case ID_DIALOG8 : // 創建一個 DatePickerDialog
dialog = new DatePickerDialog( this , new DatePickerDialog.OnDateSetListener()
{
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth)
{
String tmpstr = "" + year + "/" + (monthOfYear + 1) + "/" + dayOfMonth;
Toast.makeText (ControlDialog. this , tmpstr, Toast. LENGTH_SHORT ).show();
}
}, 2011,0, 1); // 注意:月份取值空間: 0~11
break ;
case ID_DIALOG9 : // 創建一個 TimePickerDialog
dialog = new TimePickerDialog( this , new TimePickerDialog.OnTimeSetListener()
{
public void onTimeSet(TimePicker view, int hourOfDay, int minute)
{
Toast.makeText (ControlDialog. this ,
"You picked " +hourOfDay+ " hours and " +minute+ " minutes." ,
Toast. LENGTH_SHORT ).show();
}
}, 0, 0, true );
break ;
case ID_DIALOG10 : // 創建一個 ProgressDialog
dialog = (ProgressDialog) new ProgressDialog(ControlDialog. this );
((ProgressDialog) dialog ).setIndeterminate( false );
((ProgressDialog) dialog ).setMax(10000);
((ProgressDialog) dialog ).setProgressStyle(ProgressDialog. STYLE_HORIZONTAL );
((ProgressDialog) dialog ).setTitle( " 顯示進度 " );
((ProgressDialog) dialog ).setMessage( " 我們一直在進步 ! " );
break ;
case ID_DIALOG11 : // 創建一個自定義的對話框
builder = new AlertDialog.Builder(ControlDialog. this );
LayoutInflater inflater = getLayoutInflater();
final View layout = inflater.inflate(R.layout. custom_dialog , null );
builder.setTitle( " 自定義對話框 " );
builder.setView(layout);
builder.setPositiveButton( " 確定 " , new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
EditText ed = (EditText)layout.findViewById(R.id. etname );
Toast.makeText (ControlDialog. this , ed.getText().toString(), Toast. LENGTH_LONG ).show();
dialog.dismiss(); // 可以沒有這句
}
});
dialog = builder.create();
break ;
}
// 返回創建的對話框實例
return dialog ;
}
// 在顯示之前 , 對部分對話框的屬性進行修改。
// 但, 對 CharacterPickerDialog 的屬性修改似乎無效 , 有人認爲這是 CharacterPickerDialog 本身的 bug
protected void onPrepareDialog( int id, Dialog dialog)
{
switch (id)
{
case ID_DIALOG1 :
dialog.setTitle( "A dialog with title1" );
break ;
case ID_DIALOG2 :
((AlertDialog)dialog).setTitle( "Title" );
((AlertDialog)dialog).setMessage( "Simple Information" );
break ;
case ID_DIALOG8 :
((DatePickerDialog)dialog).setTitle( " 選擇日期 " );
break ;
case ID_DIALOG9 :
((TimePickerDialog)dialog).setTitle( " 選擇時間 " );
break ;
}
}
public void onClick(View v)
{
// 點擊不同的按鈕,顯示不同的對話框
switch (v.getId())
{
case R.id. show_button1 :
this .showDialog( ID_DIALOG1 , null );
break ;
case R.id. show_button2 :
this .showDialog( ID_DIALOG2 , null );
break ;
case R.id. show_button3 :
this .showDialog( ID_DIALOG3 , null );
break ;
case R.id. show_button4 :
this .showDialog( ID_DIALOG4 , null );
break ;
case R.id. show_button5 :
this .showDialog( ID_DIALOG5 , null );
break ;
case R.id. show_button6 :
this .showDialog( ID_DIALOG6 , null );
break ;
case R.id. show_button7 :
this .showDialog( ID_DIALOG7 , null );
break ;
case R.id. show_button8 :
this .showDialog( ID_DIALOG8 , null );
break ;
case R.id. show_button9 :
this .showDialog( ID_DIALOG9 , null );
break ;
case R.id. show_button10 :
// 顯示 ProgressDialog
this .showDialog( ID_DIALOG10 , null );
// 創建線程 pt
ProgressThread pt = new ProgressThread( progressHandler );
// 啓動線程
pt.start();
break ;
case R.id. show_button11 :
this .showDialog( ID_DIALOG11 , null );
break ;
}
}
}
// 線程類:用於更新 ProgressDialog 中的進度條
class ProgressThread extends Thread
{
private Handler handler ;
public ProgressThread(Handler handler) // 傳入一個 Handler 對象
{
this . handler = handler;
}
@Override
public void run()
{
int i = 0;
while (i <= 1000)
{
handler .sendEmptyMessage(i); // i 就是 Message 中 what 的值 , handler.sendEmptyMessage
// 會觸發 handler 的 handleMessage 執行
++i;
try
{
sleep (100); // 休息 100ms
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
4. 運行結果:
點擊第一個按鈕:
點擊第二個按鈕:
試着點擊 OK 或者 Cancel 按鈕,看看 LogCat 中有什麼輸出。
點擊第三個按鈕:
點擊對話框上的三個按鈕,會有對應的 Toast 出現。
點擊第四個按鈕:
在 EditText 中輸入“ hello, android ”,在點擊 OK 按鈕,則會出現:
點擊第五個按鈕:
點擊 Item1 ,然後點擊 OK ,會出現:
點擊第六個按鈕:
選中 Item2 ,在點擊 OK 按鈕,會出現:
點擊第七個按鈕:
點擊“ 0 ”按鈕,觀察在 LogCat 中輸出。
點擊第八個按鈕:
將月份調整到 5 ,日期調整到 23 後,點擊“設置”按鈕,則會出現:
點擊第九個按鈕:
選擇不同的時間,然後點擊“設置”按鈕,觀察輸出結果。
點擊第十個按鈕:
當進度達到 100% 的時候,對話框會自動消失。
點擊第十一個按鈕:
在 EditText 中輸入一些文字,點擊“確定”按鈕,觀察輸出結果。