標籤:android des blog http java 使用
Android UI 之 Dialog 使用 引言
在現在的應用程式中,Dialog 的應用十分廣泛。常用於提示使用者一些資訊。
在應用程式中使用 Dialog
在 Android 系統中有多種內建的 Dialog 供我們使用,我們不需要再去自己動手實現它。
- AlertDialog 是一個可以顯示標題、內容、最多三個按鈕,也可以顯示普通列表、單選列表、多選列表或者自訂空間的多功能 Dialog。
- DatePickerDialog 和 TimePickerDialog 用於顯示。
安卓系統已經為我們定義好了這些 Dialog 的樣式和結構,我們只需要調用相應的方法就行。
Dialog 是所有 dialogs 的基類,我們可以直接使用 Dialog 建立 dialogs。然而 Android 官方建議我們使用 DialogFragment 類而不是直接使用 Dialog 來建立 dialogs, DialogFragment 類提供了你建立 Dialog 並控制其外觀的所有方法。並且使用 DialogFragment 去管理 Dialog 能夠確保 Dialog 正確地處理其生命回收的事件。
下面示範如何建立一個帶有標題、內容和兩個按鈕的 Dialog。首先,繼承 DialogFragment 並重寫其 onCreateDialog() 方法:
public class TraditionalDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // 建立 AlertDialog 對象 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // 為 Dialog 對象設定標題、內容、按鈕。 builder.setTitle("title") .setMessage("This is Message!") .setPositiveButton("Positive", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // do something } }) .setNegativeButton("Negative", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // do something } }); // 建立一個 Dialog 並返回給調用者 return builder.create(); }}
然後,我們在 Activity 中,建立一個 DialogFragment 並調用其中的 show() 方法以顯示 Dialog :
DialogFragment newFragment = new TraditionalDialogFragment();newFragment.show(getFragmentManager(), "DialogTest");
show() 方法的作用是顯示一個 Dialog,並把 Fragment 交給我們提供的(通過 getFragmentManager() 方法擷取的)FragmentManager 中。
其中 “DialogTest”是系統在必要時用於儲存和恢複 Fragment 狀態的一個獨一無二的標記。
AlertDialog 的幾種類型
前面說過 AlertDialog 有好幾種類型,這裡分別介紹:
普通類型
通過調用 setTitle() 方法為 Dialog 設定標題:
builder.setTitle("title");
當然,也可以從資源檔中載入標題。假設已經存在一個名為 dialog_title 的 string 資源:
builder.setTitle(R.string.dialog_title);
下面,為 Dialog 設定顯示的本文:
builder.setMessage("This is Message!");
因為其傳回型別為 Builder,你也可以直接這樣使用:
builder.setTitle("title") .setMessage("This is Message!");
當然也可以使用資源。Dialog 有最多有三個按鈕:
- Positive 這個便是我們常見的“OK、繼續”等按鈕。
- Negative 主要是我們平常用的“Cancel”。
- Neutral 這個按鈕在 Positive 和 Negative 中間,常用於“稍後提醒”
我們可以同過下面的方式添加按鈕並且處理相應的事件:
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { }});
其中,第一個參數用於設定顯示在按鈕上的文字,這裡我使用了 Android 自身內建的 cancel。後一個參數辨識為按鈕設定相應的點擊事件代碼。如果想用其他兩種按鈕,直接將其中的 Negative 換成其他的。
普通的 List
當我們需要使快顯功能表類變為一個 ListDialog 時,我們也可以直接使用 AlertDialog 為我們提供的 List。
我們可以通過如下方法為 Dialog 增加 list 的 Item:
builder.setItems(android.R.array.emailAddressTypes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { }});
setItems 為 Dialog 增加一系列的資料用於 List。第一個參數為相應的資料,我在這裡使用的是 Android 內建的一個數組資料,這個也可以自己定義。第二個參數這是 List 相應使用者操作的代碼,which 表示使用者選擇的項的索引。當然,你也可以通過 setAdapter() 方法傳入一個 ListAdapter 來動態為 List 添加資料。
需要注意的是:List 佔滿了 Dialog 內容部分,所以不能同時顯示 Message 和 List。並且,使用者一旦點擊 List 中某一個 Item,便會觸發銷毀 Dialog 的事件,所以沒有任何必要為其添加 Button(如果你願意也可以)。
單選 List
單選List在 Item 後面顯示一個選項按鈕(radio buttons):
這個和普通的 List 基本上一樣,但是不會像普通 List 一樣在點擊 item 後,觸發銷毀事件,所以還是需要我們提供按鈕來銷毀 Dialog 。添加資料也和普通 List 差不多,只需要將 setItems 換成 setSingleChoiceItems()。
多選 List
有時候需要同時選中多個資料,這時候就可以使用 MultipleList:
使用 MultipleDialog 只需要將 SingleList 中的 setSingleChoiceItem 換成下面的代碼就行:
builder.setMultiChoiceItems(android.R.array.emailAddressTypes, null, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { // do something }})
其中 isChecked 表示的是是否被選擇,因為我們可能需要記錄下使用者的選擇,這便是一個不錯的途徑。我們可以用一個 ArrayList 來儲存使用者選擇的項:
ArrayList mSelectedItems = new ArrayList();
並在 onClick 中加入下面這段代碼來記錄資料:
if (isChecked) { // If the user checked the item, add it to the selected items mSelectedItems.add(which);} else if (mSelectedItems.contains(which)) { // Else, if the item is already in the array, remove it mSelectedItems.remove(Integer.valueOf(which));}
提示:對於這種可以反饋使用者選擇資訊的控制項(Mulitiple、Single),有時可能需要在初始化的時候就選中一些使用者原始的資料。
自己定義的 Dialog
有時候需要在 Dialog 中實現一個登陸介面,但是 Android 中並沒有提供現成的 Dialog 給我們使用,這時候 CustomDialog 便派上用場了。 AlertDialog 中間的內容部分允許使用者自己定義 Layout,通過 setView() 添加到 AlertDialog 中:
預設情況下,設定的 Layout 的會充滿整個 Dialog,但是我們依然可以為其添加 Title 和 Button。以一個登陸介面為例示範如何使用 CustomDialog。
首先,得加入布局檔案Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:src="@drawable/head_logo" android:layout_width="match_parent" android:layout_height="64dp" android:scaleType="center" android:background="#FFFFBB33" android:contentDescription="@string/app_name" /> <EditText android:id="@+id/dialog_username" android:inputType="textEmailAddress" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_marginBottom="4dp" android:hint="@string/username" /> <EditText android:id="@+id/dialog_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_marginBottom="16dp" android:hint="@string/password" android:inputType="textPassword" /></LinearLayout>
通過 inflater 在 Fragment 中建立 View:
LayoutInflater inflater = getActivity().getLayoutInflater();// 因為是在 Dialog 中,父視圖填充 null。View view = inflater.inflate(R.layout.dialog_signin, null);builder.setView(view);
然後在添加按鈕:
builder.setPositiveButton("signin", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { // sign in the user ... }});builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // cancel ... }});
這樣,便實現登陸框。
將資料返回給 Dialog 的持有人
當使用者在改變資料並點擊確認的時候需要將資料返回給當前 Dialog 的持有人。要完成這個功能,首先得定義一個包含各種類型的點擊事件的介面。
public interface NoticeDialogListener { public void onDialogPositiveClick(Object object); public void onDialogNegativeClick(Object object); // ...}
然後,讓 Activity 繼承並實現相應的方法:
public class MainActivity extends Activity implements NoticeDialogListener { // ..... @Override public void onDialogPositiveClick(Object o) { // do something } @Override public void onDialogNegativeClick(Object o) { // do something } // ....}
在我們的 DialogFragment 中聲明一個 NoticeDialogListener 變數。
NoticeDialogListener mListener;
現在在 DialogFragment 中重寫 onAttach() 方法:
@Overridepublic void onAttach(Activity activity) { super.onAttach(activity); // Verify that the host activity implements the callback interface try { // Instantiate the NoticeDialogListener so we can send events to the host mListener = (NoticeDialogListener) activity; } catch (ClassCastException e) { // The activity doesn‘t implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener"); }}
onAttach() 將我們傳給 DialogFragment 的 Activity 對象中的 NoticeDialogListener 部分儲存下來,用於稍後返回資料時調用。現在在相應的事件中添加相應的代碼:
builder.setTitle("title") .setMessage("This is Message!") .setPositiveButton("Positive", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { mListener.onDialogPositiveClick(/* 加入要返回的資料 */); } }) .setNegativeButton("Negative", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { mListener.onDialogNegativeClick(/* 加入要返回的資料 */); } });
這樣便實現了將資料返回到 Dialog 的持有人那兒。當然,如果一個程式中使用了使用了多種 Dialog,都需要返回資料,那麼在我們實現的 onDialogPositiveClick 方法中,怎樣判斷資料來源?方法很多,可以為每一種 Dialog 都寫一種方法,這樣不僅重複並且效率低下。或者改寫 NoticeDialogListener :
public interface NoticeDialogListener { public void onDialogPositiveClick(int type, Object object); public void onDialogNegativeClick(int type, Object object); // ...}
並在實現該方法地方使用 switch 來匹配資訊:
public void onDialogPositiveClick(int type, Object o) { switch (type) { case 1: // traditional break; case 2: // list break; // ... default: break; }}
這樣便實現了將資料回傳給 Dialog 的持有人。
Dialog 的銷毀
如果是自訂的 Dialog 而沒有加入系統內建的按鈕時,需要我們自己實現 Dialog 的銷毀。Andorid 系統允許我們在 DialogFragment 中使用 dismiss() 方法銷毀當前的 Dialog。也有方法也可以執行銷毀工作,比如當 Dialog 正在工作時使用者點擊了 Back 按鍵,或者代碼中直接調用 onCancel() 方法,這就像點擊了 Dialog 中的 Cancel 按鈕一樣。