Dialog是Android里面用于讓用戶確認(rèn)或輸入信息的簡單的UI展現(xiàn)形式,本文將通過Demo講解如何使用Dialog。通常,我們不應(yīng)該直接使用Dialog,而是應(yīng)該使用Dialog的子類AlertDialog或DatePickerDialog以及TimePickerDialog。這三個(gè)子類對Dialog進(jìn)行了封裝,并定義了它們各自的外觀結(jié)構(gòu)。其中[AlertDialog]的樣式通常包含了確定和取消按鈕,以及標(biāo)題和一小段描述文字。DatePickerDialog和TimePickerDialog用于選擇日期和時(shí)間。
通常我們應(yīng)該使用Dialogfragment作為Dialog的容器,Dialogfragment提供了對Dialog的封裝以及生命周期的管理,可以自動處理屏幕旋轉(zhuǎn)后DialogFragment的重建(Dialog則不能),下面給出了一個(gè)DialogFragment的典型用法。
簡單的對話框
public class MyDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 設(shè)置Dialog樣式和theme
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), 0);
builder.setTitle("提示")
.setMessage("確定繼續(xù)?")
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
communicateInterface.positiveClicked();
dismiss();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
communicateInterface.negativeClicked();
dismiss();
}
});
Dialog dialog = builder.create();
return dialog;
}
}
含列表的對話框
可以在對話框里添加簡單的列表:

@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) {
// The 'which' argument contains the index position
// of the selected item
}
});
return builder.create();
}
自定義view樣式
如果需要定制對話框的展現(xiàn)樣式,可以通過自定義view的方式實(shí)現(xiàn)。方法有兩種,調(diào)用AlertDialog.Builder的setView方法,或者重寫Fragment的onCreateView方法。
方法一:重寫onCreateDialog,調(diào)用AlertDialog.Builder的setView方法
這種方法不能修改PositiveButton或NegativeButton樣式。
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 設(shè)置Dialog樣式和theme
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), 0);
builder.setTitle("提示")
.setView(getActivity().getLayoutInflater().inflate(R.layout.custom_view, null))
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
Dialog dialog = builder.create();
return dialog;
}
方法二:重寫Fragment的onCreateView方法,這樣就不會使用默認(rèn)的Dialog樣式,而是完全的自定義樣式
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.custom_view_2, container, false);
TextView cancel = (TextView) view.findViewById(R.id.cancel_action);
TextView confirm = (TextView) view.findViewById(R.id.confirm_action);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
Dialog和Activity交互
通過DialogFragment的onAttach方法,可以將宿主Activity/Fragment的實(shí)例傳進(jìn)來,從而能在DialogFragment中調(diào)用宿主Activity/Fragment的函數(shù)。
public interface CommunicateInterface {
void positiveClicked();
void negativeClicked();
}
public class MainActivity extends AppCompatActivity implements CommunicateInterface {
...
@Override
public void positiveClicked() {
Toast.makeText(this, "繼續(xù)下一關(guān)", Toast.LENGTH_SHORT).show();
}
@Override
public void negativeClicked() {
Toast.makeText(this, "取消", Toast.LENGTH_SHORT).show();
}
...
}
public class MyDialogFragment2 extends DialogFragment {
private CommunicateInterface communicateInterface;
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
communicateInterface = (CommunicateInterface) activity;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
communicateInterface.negativeClicked();
dismiss();
}
});
confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
communicateInterface.positiveClicked();
dismiss();
}
});
return view;
}
}
Dialog展示
DialogFragment既可以作為Dialog占用一部分屏幕空間展示,也可以作為一個(gè)Fragment全屏展示,通過不同的添加方式實(shí)現(xiàn)這兩種展示。
通過DialogFragment的show方法,會使Dialog占用一部分屏幕空間展示:
@OnClick(R.id.show_as_dialog_tv)
public void onShowAsDialogTVClicked(View v) {
DialogFragment dialogFragment = new MyDialogFragment2();
dialogFragment.show(getFragmentManager(), "dialog3");
}
通過FragmentTransation添加DialogFragment可以實(shí)現(xiàn)全屏展示:
@OnClick(R.id.show_as_fragment_tv)
public void onShowAsFragmentTVClicked(View v) {
DialogFragment dialogFragment = new MyDialogFragment2();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(dialogFragment, "diglog4")
.addToBackStack(null)
.commit();
}
這種情況有個(gè)限制,只能通過重寫onCreateView方法實(shí)現(xiàn)自定義view,而不能通過AlertDialog.build方式。
[Note]:** 雖然Android Developer文檔提到,可以通過FragmentTransation添加DialogFragment實(shí)現(xiàn)全屏,但是實(shí)際測試結(jié)果表明,展示的Dialog仍然不是全屏,可參照Demo里的實(shí)現(xiàn)運(yùn)行查看效果。具體原因未知。如果要全屏展示直接使用Fragment就行了,也不需要使用DialogFragment,所以此處未深究原因。
普通的Activity也可以作為Dialog展示,比如在超大屏幕上,不適合滿屏展示的情況下。如下設(shè)置theme即可。
<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >
Dialog取消展示
可以通過dismiss函數(shù)停止Dialog的展示,或者通過cancel取消Dialog的展示,前者發(fā)生在點(diǎn)擊確定或取消按鈕的時(shí)候,后者發(fā)生在按返回鍵或者點(diǎn)擊Dialog之外的屏幕范圍的時(shí)候。通過在DialogFragment中重寫onDismiss和onCancel方法,可以加入對這兩種事件的處理。注意,這里不能直接調(diào)用Dialog的setOnCancelListener或者setOnDismissListener方法設(shè)置回調(diào)函數(shù),必須重寫onDismiss或onCancel,否則報(bào)錯(cuò):
java.lang.IllegalStateException: You can not set Dialog's OnCancelListener or OnDismissListener
Android Develop文檔的描述:
Note:
DialogFragment own the Dialog.setOnCancelListener and Dialog.setOnDismissListener callbacks.
You must not set them yourself.
To find out about these events, override onCancel(DialogInterface) and onDismiss(DialogInterface)
當(dāng)調(diào)用DialogFragment的cancel方法時(shí),兩個(gè)回調(diào)函數(shù)都會被調(diào)用;當(dāng)調(diào)用dismiss方法時(shí),只調(diào)用onDismiss會被調(diào)用。
Dialog展示W(wǎng)ebView,監(jiān)聽后退鍵
如果在Dialog里嵌入WebView進(jìn)行頁面展示,那需要對返回鍵進(jìn)行監(jiān)聽,以確定按返回鍵的時(shí)候是后退到上一個(gè)頁面還是退出dialog,通過重寫onDismiss或onCancel都無法實(shí)現(xiàn)這個(gè)功能,會直接退出dialog。正確的寫法是對dialog進(jìn)行設(shè)置onKeyListener,代碼如下:
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& keyEvent.getAction() == MotionEvent.ACTION_UP
&& webView.canGoBack()) {
webView.goBack();
return true; // pretend we've processed it
}
else
return false; // pass on to be processed as normal
}
});
參考:
https://developer.android.com/guide/topics/ui/dialogs.html
https://developer.android.com/reference/android/app/DialogFragment.html