第三部分:Android 应用程序接口指南---第二节:UI---第六章 对话框
第6章 對話框
一個對話框是一個小窗口,提示用戶做出決定或輸入額外的信息,一個對話框不填充屏幕并且通常用于在程序運(yùn)行時中斷,然后彈出通知提示用戶,從而直接影響到正在運(yùn)行的程序。圖6-1就是對話框的外觀。
?
圖6-1
Dialog類是所有具體對話框的基類,但你應(yīng)該避免直接實例化Dialog。因為可能有些現(xiàn)成的已經(jīng)給你提供好了,比如以下幾種:
◆AlertDialog
一個對話框,可以顯示一個標(biāo)題(可選),三個按鈕(可選),內(nèi)容的列表(可選),或一個自定義布局。
◆DatePickerDialog或TimePickerDialog
一個對話框,其中有一個預(yù)定義的用戶界面,允許用戶選擇一個日期或時間。
◆ProgressDialog
這個我們應(yīng)該盡量避免使用,它用于顯示進(jìn)度條。但是,如果你如果需要顯示這種加載或不確定的進(jìn)度情況,更好的方法是Activity結(jié)合Progress,明確的在布局中使用ProgressBar來更新進(jìn)度,以讓用戶明確的看到進(jìn)度情況。
以上這些類定義了你對話框的風(fēng)格和結(jié)構(gòu),但你也可以使用DialogFragment作為你對話框的容器。DialogFragment類提供所有創(chuàng)建和管理外觀的控制力,它比直接調(diào)用Dialog對象中的方法更好。使用DialogFragment管理對話框可以確保它正確地處理生命周期事件,比如當(dāng)用戶按下后退按鈕或旋轉(zhuǎn)屏幕時。這個DialogFragment類還允許您重用對話框的用戶界面,就像一個傳統(tǒng)的Fragment (比如當(dāng)你希望對話框在大型和小型屏幕中的UI不一樣)。注意DialogFragment類在android3.0或以上版本中才有,如果你需要在低版本中使用它可以使用Support Library,添加這個庫到你的應(yīng)用中。一般比較新的ADT+Eclipse套裝會自動把這個庫添加到你的項目中。
6.1 創(chuàng)建一個對話框Fragment
你能完成各種各樣的對話框設(shè)計:包括自定義布局和那些描述。通過DialogFragment創(chuàng)建一個AlertDialog并在onCreateDialog()回調(diào)方法中設(shè)置一些屬性。如代碼清單6-1所示:
public class FireMissilesDialogFragment extends DialogFragment {@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {// 使用Builder類更方便AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setMessage(R.string.dialog_fire_missiles).setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {//相當(dāng)于確定 }}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {// 相當(dāng)于取消 }});// 創(chuàng)建AlertDialog對象并返回return builder.create();} }?
代碼清單6-1
現(xiàn)在當(dāng)你創(chuàng)建完后調(diào)用show()方法,對話框出現(xiàn)圖6-2的效果。
?
圖6-2 一個對話框中帶有一個消息和兩個動作按鈕
6.2 構(gòu)建一個Alert Dialog
AlertDialog類允許您構(gòu)建各種對話框設(shè)計。如圖6-3所示, 一個警告對話框有三個區(qū)域
?
圖6-3 對話框布局
1. 標(biāo)題(Title)
這是可選的,如果你需要一個簡單的信息或問題的狀態(tài),你可以不需要一個標(biāo)題。
2. 內(nèi)容區(qū)域
它可以顯示一條消息,一個列表,或其他自定義布局。
3. 動作按鈕
在一個對話框最多不應(yīng)該超過3個按鈕。
AlertDialog.Builder類系統(tǒng)了API允許你創(chuàng)建各種各樣的內(nèi)容,包括布局等,現(xiàn)在在返回看下代碼清單6-1可能你會更清晰了。清單中還有兩個按鈕,如果你看到這樣的格式方法如set..Button(),就是設(shè)置動作按鈕了,下面讓我們來看下3種按鈕的不同之處:
◆Positive
這個按鈕表示接受或著繼續(xù),相當(dāng)于“確定”或者“OK”
◆Negative
這個按鈕相當(dāng)于“取消”
◆Neutral
這是個中立按鈕,比如一個“以后提醒我”的功能。
每種按鈕只能出現(xiàn)一次,不能同時出現(xiàn)N次。
6.2.1添加一個List
有三種可用的AlertDialog API列表:
一個傳統(tǒng)的單選列表
一個持久化的單選列表(單選按鈕)
一個持久化的多選列表(復(fù)選框)
創(chuàng)建一個單選列表類似于圖6-4,你可以使用setItems()方法,如代碼清單6-2所示:
?
?
圖6-4 這個對話框里有標(biāo)題和列表
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setTitle(R.string.pick_color);.setItems(R.array.colors_array, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// 'which' 參數(shù)包含被選中item的索引位置 }});return builder.create(); }?
代碼清單6-2
因為列表出現(xiàn)在對話框的內(nèi)容區(qū)域里,對話框不能既顯示列表又顯示一個消息,所以你可以使用setTitle()設(shè)置標(biāo)題以代替消息(message)。為了指定列表中的item,你可以通過數(shù)組來調(diào)用setItems()方法。或者你能使用setAdapter()來指定一個列表。它允許你使用一個ListAdapter來返回列表和動態(tài)數(shù)據(jù)。如果你選擇使用ListAdapter返回一個列表,那么請一直使用Loader以便內(nèi)容異步加載。關(guān)于這方面的內(nèi)容在“用戶界面和布局”和“裝載機(jī)”章節(jié)我們已講述過。注意:默認(rèn)情況下,觸摸一個list item會dissmiss掉一個對話框,除非你使用下面我們要講述的持久化選擇列表。
6.2.2添加一個持久化的單選或多選列表
為了添加一個列表的多選item或單選item,你可以使用setMultiChoiceItems()或setSingleChoiceItems()方法。例如圖6-5是在一個ArrayList中使用多選item的例子。
?
圖6-5 一個多選列表的items
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {mSelectedItems = new ArrayList(); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setTitle(R.string.pick_toppings).setMultiChoiceItems(R.array.toppings, null,new DialogInterface.OnMultiChoiceClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which,boolean isChecked) {if (isChecked) {// 如果選擇一個item,就添加一個索引 mSelectedItems.add(which);} else if (mSelectedItems.contains(which)) {// 否則,如果item已經(jīng)存在就移除它 mSelectedItems.remove(Integer.valueOf(which));}}})// 設(shè)置動作按鈕.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// 用戶點(diǎn)擊OK,保存已選中的item結(jié)果到某處或者返回結(jié)果到已打開的對話框中 ...}}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {...}});return builder.create(); }?
代碼清單6-3
雖然一個傳統(tǒng)的列表和一個單選列表都提供一個“單選”動作。但如果你想要保存用戶的選擇,你應(yīng)該使用setSingleChoiceItems()。就是說如果你稍后再次打開對話框應(yīng)該表明用戶當(dāng)前的選擇是什么,然后你使用單選按鈕創(chuàng)建一個列表。
6.2.3創(chuàng)建以自定義的布局
如果你想要一個自定義的布局,那么你可以使用AlertDialog.Builder對象中的setView()方法來添加一個你創(chuàng)建的布局。默認(rèn)情況下,自定義布局會填充對話框窗口,但你仍然能使用AlertDialog.Builder中的方法來添加動作按鈕和標(biāo)題。例如,圖6-6和代碼清單6-4所示:
?
圖6-6 一個自定義的對話框布局
代碼文件在res/layout/dialog_signin.xml中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:src="@drawable/header_logo"android:layout_width="match_parent"android:layout_height="64dp"android:scaleType="center"android:background="#FFFFBB33"android:contentDescription="@string/app_name" /><EditTextandroid:id="@+id/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" /><EditTextandroid:id="@+id/password"android:inputType="textPassword"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:fontFamily="sans-serif"android:hint="@string/password"/> </LinearLayout>?
代碼清單6-4
注意:默認(rèn)情況下,當(dāng)你設(shè)置一個EditText元素為“textPassword”輸入類型時,字體會設(shè)置為等寬字體,因此你應(yīng)該使用字體為“sans-serif”來統(tǒng)一匹配文本字體風(fēng)格。為了在DialogFragment 中inflate布局,你可以使用getLayoutInflater()獲得一個LayoutInflater并調(diào)用inflate(),然后setView()。如代碼清單6-5所示:
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());// 獲得layout inflaterLayoutInflater inflater = getActivity().getLayoutInflater();builder.setView(inflater.inflate(R.layout.dialog_signin, null))//設(shè)置action響應(yīng).setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// todo... }}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {LoginDialogFragment.this.getDialog().cancel();}}); return builder.create(); }?
代碼清單6-5
注意:如果你想要自定義對話框,你其實可以使用Activity來作為對話框。簡單的創(chuàng)建一個activity然后在manifest中的<activity>節(jié)點(diǎn)下設(shè)置它的主題(theme)為Theme.Holo.Dialog即可。如代碼清單6-6所示:
<activity android:theme="@android:style/Theme.Holo.Dialog" >?
代碼清單6-6
就是這樣。這個activity現(xiàn)在作為一個對話框窗口顯示而不是全屏顯示。
6.3 通過事件返回到對話框的Host
當(dāng)用戶觸摸一個對話框的動作按鈕或選擇一個item時,你的DialogFragment可能執(zhí)行必要的操作,但常常你想要傳遞這個事件到已經(jīng)打開的對話框中的上層activity或fragment中。為了做到這些,定義一個點(diǎn)擊事件的接口類型。然后實現(xiàn)接口中的方法。如代碼清單6-7所示:
public class NoticeDialogFragment extends DialogFragment {public interface NoticeDialogListener {public void onDialogPositiveClick(DialogFragment dialog);public void onDialogNegativeClick(DialogFragment dialog);}NoticeDialogListener mListener;@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);try {mListener = (NoticeDialogListener) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString()+ " must implement NoticeDialogListener");}}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {// Build the dialog and set up the button click handlersAlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setMessage(R.string.dialog_fire_missiles).setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {// 發(fā)送positive按鈕事件回調(diào)到host activitymListener.onDialogPositiveClick(NoticeDialogFragment.this);}}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {// 發(fā)送negative按鈕事件回調(diào)到host activitymListener.onDialogPositiveClick(NoticeDialogFragment.this);}});return builder.create();}}?
代碼清單6-7
代碼清單6-7只是定義接口,當(dāng)然我們還需要實現(xiàn)這個接口,下面代碼清單6-8就是如何實現(xiàn)并運(yùn)用的:
public class MainActivity extends FragmentActivityimplements NoticeDialogFragment.NoticeDialogListener{...public void showNoticeDialog() {DialogFragment dialog = new NoticeDialogFragment();dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");}@Overridepublic void onDialogPositiveClick(DialogFragment dialog) {}@Overridepublic void onDialogNegativeClick(DialogFragment dialog) {} }?
代碼清單6-8
6.4 顯示一個對話框
當(dāng)你想要顯示你的對話框時,創(chuàng)建一個DialogFragment的實例并調(diào)用show()方法,并傳遞一個FragmentManager和一個標(biāo)簽名字。你可以通過getSupportFragmentManager()來獲得一個FragmentManager。如代碼清單6-9所示:?
public void confirmFireMissiles() {DialogFragment newFragment = new FireMissilesDialogFragment();newFragment.show(getSupportFragmentManager(), "missiles"); }?
代碼清單6-9
第二個參數(shù),"missiles"是一個唯一的標(biāo)簽名,因為某些必要情況下系統(tǒng)用來保存和恢復(fù)fragment的狀態(tài)。當(dāng)然你可以通過findFragmentByTag()來獲得一個fragment。
6.5 顯示一個全屏對話框或作為一個嵌入式
你可能有一個UI設(shè)計,你想要一個區(qū)域用來放置這個UI,這里你用到了一個對話框,但有時候你又需要全屏顯示(比如在大屏幕下可能作為標(biāo)準(zhǔn)的對話框,在小屏幕下你可能需要全屏)。DialogFragment類提供了這種靈活性。但是,你不能使用AlertDialog.Builder或其他Dialog對象來處理這種情況。如果你想要DialogFragment是可嵌入的,你必須在布局中定義對話框的UI,然后在onCreateView()回調(diào)方法中載入布局。如代碼清單6-10所示(purchase_items.xml):
public class CustomDialogFragment extends DialogFragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.purchase_items, container, false);}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Dialog dialog = super.onCreateDialog(savedInstanceState);dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);return dialog;} }?
代碼清單6-10
下面是一些代碼,根據(jù)屏幕大小決定是否顯示Fragment作為一個對話框或全屏UI,如代碼清單6-11所示:
public void showDialog() {FragmentManager fragmentManager = getSupportFragmentManager();CustomDialogFragment newFragment = new CustomDialogFragment();if (mIsLargeLayout) {// 如果是大型布局,作為對話框顯示即可newFragment.show(fragmentManager, "dialog");} else {// 如果是小設(shè)備,作為fragment全屏顯示FragmentTransaction transaction = fragmentManager.beginTransaction();//指定一個過渡動畫 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);// 使用全屏就把對話框newFragment作為根view transaction.add(android.R.id.content, newFragment).addToBackStack(null).commit();} }?
代碼清單6-11
在這個例子中,mIsLargeLayout這個boolean值是我們代碼檢測出來的結(jié)果,其實更好的方法是在不同的文件夾下指定資源值,如下所示:
res/values/bools.xml
<!—默認(rèn)boolean值 --> <resources><bool name="large_layout">false</bool> </resources>?
res/values-large/bools.xml
<!—Large屏幕下的boolean值--> <resources><bool name="large_layout">true</bool> </resources>?
然后再代碼中這樣獲取如代碼清單6-12所示:
boolean mIsLargeLayout; @Override public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mIsLargeLayout = getResources().getBoolean(R.bool.large_layout); }?
代碼清單6-12
6.5.1 在大屏幕下顯示一個以對話框形式的activity
有個很簡單的方法就是,如代碼清單6-13所示:
<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >?
代碼清單6-13
6.6 Dissmiss對話框
當(dāng)用戶觸摸任何一個由AlertDialog.Builder創(chuàng)建動作按鈕時,系統(tǒng)會dismiss掉對話框。當(dāng)用戶觸摸一個對話框的itme時系統(tǒng)會dismiss對話框,除單選按鈕或復(fù)選框之外。當(dāng)然你也能手動調(diào)用DialogFragment的dismiss()的方法。如果你需要當(dāng)對話框消失時,執(zhí)行某些操作,你可以在DialogFragment中實現(xiàn)onDismiss()方法。當(dāng)然有些時候你想取消一個對話框。如果用戶按下返回按鈕,觸摸對話框外面區(qū)域或調(diào)用Dialog的cancel()方法都會執(zhí)行取消操作,或者你可以在DialogFragment中實現(xiàn)onCancel()方法來做一些取消之前的操作。注意:系統(tǒng)會優(yōu)先調(diào)用onDismiss()。如果你主動調(diào)用了Dialog.dismiss()或者DialogFragment.dismiss()那么系統(tǒng)會調(diào)用onDismiss()而不會調(diào)用onCancel()。所以通常情況下我們都使用dismiss()來關(guān)閉對話框。
??本文來自jy02432443,是本人辛辛苦苦一個個字碼出來的,轉(zhuǎn)載請保留出處,并保留追究法律責(zé)任的權(quán)利?QQ78117253?
轉(zhuǎn)載于:https://www.cnblogs.com/tianjian/p/3482340.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的第三部分:Android 应用程序接口指南---第二节:UI---第六章 对话框的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML5地区自转代码
- 下一篇: Android中GridView使用总结