android中對話框是很是經常使用的控件之一, google也提供了各類自定義對話框. 我以爲好多人都太模糊. 因此我全面的總結下.java
對話框的幾種實現方式:android
關鍵類ios
AlertDialog翻譯過來就是警示對話框, 其實就是通常的對話框也是最經常使用的;編程
這裏有個關鍵類: AlertDialog.Builder. 屬於構造器模式用法.數組
這裏演示最簡單的對話框緩存
代碼bash
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("標題");
builder.setMessage("信息");
builder.show();
複製代碼
上面介紹了最基本的AlertDialog的使用. 可是在開發中須要更復雜的功能實現. 因此我會介紹下全部的方法app
Builder是屬於AlertDialog的內部類. 負責建立AlertDiglog的構造器. 因此屬於鏈式編程.ide
正由於是構造器模式, AlertDialog的全部方法你均可以直接忽略, Builder已經實現了全部的功能. 而且AlertDialog是Protected權限沒法直接建立對象的.函數
雖然叫作肯定和取消按鈕, 不過你設置成別的名稱或者功能均可以.
builder.setPositiveButton("肯定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 點擊事件的回調方法
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
複製代碼
左邊按鈕(取消)
AlertDialog.Builder setPositiveButton (int textId, // 字符串數組資源id DialogInterface.OnClickListener listener) AlertDialog.Builder setPositiveButton (CharSequence text, // 字符串 DialogInterface.OnClickListener listener) 複製代碼
右邊按鈕(肯定)
AlertDialog.Builder setNegativeButton (CharSequence text, DialogInterface.OnClickListener listener) AlertDialog.Builder setNegativeButton (int textId, DialogInterface.OnClickListener listener) 複製代碼
中立按鈕(隨便你寫啥). 這個按鈕位於取消和肯定中間的一個.
AlertDialog.Builder setNeutralButton (CharSequence text, DialogInterface.OnClickListener listener) AlertDialog.Builder setNeutralButton (int textId, DialogInterface.OnClickListener listener) 複製代碼
注意全部的條目選擇方法都不能和setMessage同時使用. 不然無效. 而且選中任何條目都將關閉對話框.
AlertDialog.Builder setItems (int itemsId, DialogInterface.OnClickListener listener) AlertDialog.Builder setItems (CharSequence[] items, DialogInterface.OnClickListener listener) 複製代碼
該對話框和傳統的單選對話框的區別是選中條目後能夠不自動關閉對話框. 而且能夠設置默認選中的條目.
AlertDialog.Builder setSingleChoiceItems (int itemsId, // 資源數組id int checkedItem, // 選中狀態的條目索引. 若是默認不選中任何, 寫-1 DialogInterface.OnClickListener listener) AlertDialog.Builder setSingleChoiceItems (ListAdapter adapter, // ListView的適配器 int checkedItem, DialogInterface.OnClickListener listener) AlertDialog.Builder setSingleChoiceItems (Cursor cursor, // 用遊標來建立條目 int checkedItem, String labelColumn, DialogInterface.OnClickListener listener) AlertDialog.Builder setSingleChoiceItems (CharSequence[] items, // 字符串數組, 最經常使用簡單的. int checkedItem, DialogInterface.OnClickListener listener) 複製代碼
AlertDialog.Builder setMultiChoiceItems (CharSequence[] items, // 條目數組 boolean[] checkedItems, // 選擇狀態數組 ,若是不想默認選中任何, 可寫null DialogInterface.OnMultiChoiceClickListener listener) AlertDialog.Builder setMultiChoiceItems (int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener) AlertDialog.Builder setMultiChoiceItems (Cursor cursor, // 採用遊標的方式 String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener) 複製代碼
參數介紹:
示例
final String[] itemTitles = {"象拔蚌", "鮑魚", "壽桃包"};
builder.setMultiChoiceItems(itemTitles, null, new DialogInterface.OnMultiChoiceClickListener() {
/** * 在選中對話框條目的時候回調 * @param dialog 對話框, 可用於在該回調方法內部調用dismiss關閉對話框 * @param which 當前被選中的條目索引 * @param isChecked 被選擇狀態 */
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
// 吐司
Toast.makeText(MainActivity.this, itemTitles[which], Toast.LENGTH_SHORT).show();
dialog.dismiss(); // 關閉對話框
}
});
複製代碼
這兩種方式不多使用. 由於相對比較複雜.
做用和setMultiChoiceItems以及setSingleChoiceItems同樣.
至關於使用ListView的適配器ListAdapter來設置選擇條目的顯示內容. 能夠顯示更加豐富的內容.
AlertDialog.Builder setAdapter (ListAdapter adapter, DialogInterface.OnClickListener listener) 複製代碼
詳情請去了解Cursor
AlertDialog.Builder setCursor (Cursor cursor, DialogInterface.OnClickListener listener, String labelColumn) 複製代碼
AlertDialog create () // 建立只是返回一個AlertDialog對象. 並不會顯示該對話框 AlertDialog show () // 直接顯示對話框 複製代碼
獲得建立AlertDialog時所傳入的上下文對象.
Context getContext () 複製代碼
默認爲true, 即點擊對話框外部會關閉對話框. 若是false則不會關閉
AlertDialog.Builder setCancelable (boolean cancelable) 複製代碼
AlertDialog.Builder setTitle (CharSequence title) AlertDialog.Builder setTitle (int titleId) 複製代碼
上面的方法標題只是文字的形式而已. 而下面的方法能夠在標題的位置自定義任何view對象來顯示.
AlertDialog.Builder setCustomTitle (View customTitleView) 複製代碼
即在標題的左邊加上一個圖片做爲圖標顯示
AlertDialog.Builder setIcon (Drawable icon) AlertDialog.Builder setIcon (int iconId) 複製代碼
還有一個經過主題的屬性來設置對話框圖標. 我不懂
AlertDialog.Builder setIconAttribute (int attrId) 複製代碼
能夠自定義對話框顯示任何內容. 注意即便你自定義了對話框. 你若是使用設置肯定和取消按鈕依舊會顯示;
AlertDialog.Builder setView (int layoutResId) // 佈局文件便可 AlertDialog.Builder setView (View view) // View對象 複製代碼
輸入框的問題:
若是給AlertDialog自定義View裏面插入了EditText是沒法彈出鍵盤的, 能夠添加如下代碼
Window alertDialogWindow = mAlertDialog.getWindow();
alertDialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
複製代碼
若是想輸入框自動彈出
alertDialogWindow.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
複製代碼
取消監聽器是點擊對話框外部的方式關閉了對話框. 調用dismiss方法關閉的時候不會回調
AlertDialog.Builder setOnCancelListener (DialogInterface.OnCancelListener onCancelListener) 複製代碼
該監聽器是在AlertDialog調用了dismiss()方法或者點擊了對話框外部都會回調的監聽器.
AlertDialog.Builder setOnDismissListener (DialogInterface.OnDismissListener onDismissListener) 複製代碼
該方法是你將ListAdapter設爲對話框條目顯示的時候使用的方法
AlertDialog.Builder setOnItemSelectedListener (AdapterView.OnItemSelectedListener listener)
複製代碼
能夠接受按鍵的事件. 可用於在彈出對話框後屏蔽按鍵.
AlertDialog.Builder setOnKeyListener (DialogInterface.OnKeyListener onKeyListener) 複製代碼
若是徹底不須要AlertDialog的任何元素(按鈕/標題/點擊事件)能夠繼承Dialog自定義實現, 固然我是不推薦仿IOS對話框的;
若是徹底使用自定義的對話框我更推薦DialogFragment來實現(後面講解)
Dialog若是存在輸入框是沒法自動彈出鍵盤的, 如下函數能夠實現;
public static void showInputMethod(EditText editText) {
editText.setFocusable(true);
editText.setFocusableInTouchMode(true);
editText.requestFocus();
InputMethodManager imm = (InputMethodManager) Library.getApp()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
}
}
複製代碼
AlertDialog能夠設置列表, 可是沒有設置分隔物的函數;
public static void setDivider(AlertDialog dialog, @DrawableRes int divider) {
ListView listView = dialog.getListView();
if (listView != null) {
listView.setOverscrollFooter(new ColorDrawable(Color.TRANSPARENT));
listView.setDivider(Res.getDrawable(divider));
}
}
複製代碼
public static void setTransparent(Dialog dialog) {
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawableResource(android.R.color.transparent);
}
}
複製代碼
DialogFragment 設置主題, 缺點: 強制最大寬度
dialog.setStyle(
androidx.fragment.app.DialogFragment.STYLE_NO_TITLE,
android.R.style.Theme_Material_Light_Dialog_MinWidth
)
複製代碼
將佈局再多包裹一層. 由於DialogFragment頂層的尺寸會失效, 可是Dialog不會. 缺點: 只能設置固定值
設置Window佈局參數, 缺點: 只能設置固定值
Dialog有一個默認的寬度, 高度是包裹適應的; 可是有時候仍是須要控制的; 注意必定要在對話框顯示以後執行如下函數;
除了以上的警示對話框的使用外. 還提供一種單獨的對話框樣式. 進度條對話框. 進度條是計算機應用歷史上一個偉大的發明.
ProgressDialog progressDialog = new ProgressDialog(this);// 建立進度對話框對象
progressDialog.setTitle("標題"); // 設置標題
progressDialog.setMessage("加載中..."); // 設置消息
progressDialog.show(); // 顯示進度條
複製代碼
除了上面這種默認進度條樣式, Google還提供設置樣式水平進度條
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
//ProgressDialog.STYLE_SPINNER 旋轉進度條, 默認就是這種樣式
複製代碼
ProgressDialog是AlertDialog的子類. 繼承了其全部方法. 因此這裏我只講新增的方法.
既然是進度對話框固然提供設置進度的方法, 默認的旋轉進度條樣式是沒法設置進度的. 該方法必須在show()後面執行才生效.
int getProgress () void setProgress (int value) 複製代碼
void setMax (int max) int getMax () 複製代碼
能夠用父類的show()
方法. 也能夠用ProgressDialog新增的靜態方法直接一行代碼顯示.相似於Toast的用法.
ProgressDialog show (Context context, // 上下文 CharSequence title, // 標題 CharSequence message) // 消息內容 ProgressDialog show (Context context, CharSequence title, CharSequence message, boolean indeterminate) ProgressDialog show (Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable) ProgressDialog show (Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable, DialogInterface.OnCancelListener cancelListener) 複製代碼
相似於你看視頻的時候的緩存進度條. 比主進度條的顏色淺一些.
void setSecondaryProgress (int secondaryProgress) int getSecondaryProgress () 複製代碼
和setProgress的區別是該修改是在原有的進度基礎上增長或者減小. 而且不須要在意在show()方法以前仍是以後.
void incrementProgressBy (int diff) // 進度增長 void incrementSecondaryProgressBy (int diff) // 次要進度增長 複製代碼
該效果只針對水平進度條. 進度條的狀態顯示在不斷地變化.
void setIndeterminate (boolean indeterminate) // 默認爲false. true開啓效果 boolean isIndeterminate () // 是否處於不肯定狀態 void setIndeterminateDrawable (Drawable d) // 設置一個圖片做爲不肯定進度的顯示 複製代碼
void setProgressStyle (int style) 複製代碼
包括兩個參數:
該方法只有在ProgressDialog爲水平樣式時纔有效.
void setProgressDrawable (Drawable d) 複製代碼
void setProgressNumberFormat (String format) 複製代碼
使用一個字符串來格式化的進度對話框右下角的文字內容. 若是傳入null將不顯示任何內容.
%1d: 當前進度百分比
%2d: 最大進度百分比
舉個例子若是想顯示下載內容的大小(/kb爲單位) , 能夠這麼寫
setProgressNumberFormat("%1dkb/%2dkb")
複製代碼
固然你隨便寫個內容也行
這裏用到一個類NumberFormat, 該類是格式化數字的工具. 抽象類須要經過getInstance**()方法建立對象. 這個類方法有點多我就不細講了. 這個百分比格式化用的也少.
參數設爲null, 進度條左下角的百分比將不會顯示.
void setProgressPercentFormat (NumberFormat format) 複製代碼
示例:
// getCurrencyInstance 是一個貨幣格式化的方法
dialog.setProgressPercentFormat(NumberFormat.getCurrencyInstance());
複製代碼
ProgressBar是做爲控件使用的進度條. 且只能寫在佈局文件中使用. ProgressDialog的實現原理就是建立一個包含了ProgressDialog的View顯示.
進度條對話框還能夠在佈局文件中直接寫入做爲控件, 同時該類只能夠在佈局中使用纔會顯示. 系統提供的水平進度樣式. StyleProgressBar.Horizontal
<ProgressBar style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal" android:progress="50" android:max="100" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content"/ />
複製代碼
順帶一提, 進度條不能在子線程開啓(show)可是能夠在子線程關閉(dismiss).
該類屬於Fragment的子類, 也是官方推薦的對話框.
對於須要自定義的對話框內容我是推薦DialogFragment的. 普通對話框推薦使用默認的altertDialog 強烈不推薦ios效果的滾輪控件, 什麼年代的設計, 醜並且不方便
和通常的Fragment同樣用法.
public class CustomDialogFragment extends DialogFragment {
/** * 和通常Fragment的onCreate方法同樣 * * @param inflater * @param container * @param savedInstanceState * @return 返回View對象 */
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
/** * 用於在Fragment裏面嵌套Dialog, 和上面的方法兩選一實現便可. * 若是兩個都寫了只有這個方法生效 * * @param savedInstanceState * @return 返回Dialog對象 */
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return super.onCreateDialog(savedInstanceState);
}
}
複製代碼
在Activity裏面顯示
new CustomDialogFragment().show(getSupportFragmentManager(), "bag");
複製代碼
※ 注意DialogFragment若是使用的是onCreateView的話. 佈局文件的根佈局不管是match_parent仍是給定值都算做wrap_content. 要想控制對話框的尺寸就寫個子容器佈局.
DialogFragment沒法全屏顯示
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" >
<TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="程序吳彥祖" />
</RelativeLayout>
</RelativeLayout>
複製代碼
這裏介紹的都是用於重寫的週期回調方法. 注意DialogFragment是Fragment的子類. 包括Fragment的全部生命週期
當dismiss方法關閉對話框時回調該方法
void onDismiss (DialogInterface dialog) 複製代碼
點擊DialogFragment外部取消對話框回調的方法
void onCancel (DialogInterface dialog) 複製代碼
用於調用的方法
void show (FragmentManager manager, String tag) // 標籤. 這些參數其實只要會Fragment都能看懂. int show (FragmentTransaction transaction, String tag) 複製代碼
void dismiss () 複製代碼
即點擊對話框外部是否能夠關閉對話框
void setCancelable (boolean cancelable) boolean isCancelable () 複製代碼
Dialog getDialog () // 獲得onCreateDialog方法返回的Dialog對象 複製代碼
若是設爲false則將和Fragment同樣建立佈局而不是對話框. 這個方法須要在onCreateDialog方法以前執行纔有效. 推薦onCreate方法裏面執行 . 不過若是你設爲false, DialogFragment的show方法將無效.
該方法沒啥卵用.
boolean getShowsDialog () void setShowsDialog (boolean showsDialog) // 默認爲true 複製代碼
必須在onCreateDialog方法執行前調用. 即onCreate方法裏面調用.
void setStyle (int style, // 樣式 int theme) // 主題, 若是0則使用默認主題 複製代碼
style支持四種參數值:
對應獲得setStyle()
方法設置的主題.
int getTheme ()
複製代碼
詳情看Fragment的commitAllowingStateLoss方法
void dismissAllowingStateLoss ()
複製代碼
關於寬度被限制到範圍的問題
// 解決寬度限制問題
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog_MinWidth);
// 透明背景
getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
複製代碼
Activity做爲對話框. 只須要在主題中繼承dialog的主題便可. 而後正常打開該activity便可.
示例
<style name="CustomDialog" parent="@android:style/Theme.Dialog"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowNoTitle">true</item> </style>
複製代碼
這裏我取消了標題欄和背景透明.
※ 注意activity的根佈局千萬不要設置爲match_parent全屏顯示.
added in version 23.2.0
示例代碼
public class MainActivity extends AppCompatActivity {
private BottomSheetDialog mDialog;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mDialog = new BottomSheetDialog(this);
mDialog.setContentView(R.layout.dialog_bottom_sheet);
}
@OnClick(R.id.button) public void onClick() {
mDialog.show();
}
}
複製代碼
Dialog建立須要代碼構建實例對象不用我多說
構造方法
BottomSheetDialog(Context context)
BottomSheetDialog(Context context, int theme)
複製代碼
設置選項
void setCanceledOnTouchOutside(boolean cancel) // 觸摸範圍外取消對話框 void setCancelable(boolean cancelable) // 返回鍵和觸摸範圍外都不能取消對話框 // 設置對話框內容 void setContentView(View view) void setContentView(int layoutResId) void setContentView(View view, ViewGroup.LayoutParams params) 複製代碼
前面介紹過DialogFragment
. 而這裏提到的BottomSheetDialogFragment
用法一致. 不另做介紹.
僅僅是上拉對話框就太簡單了, Android提供CoordinatorLayout.Behavior的實現類BottomSheetBehavior
來配合CoordinatorLayout佈局使用. 實現更美觀的MaterialDesign交互效果.
相對於BottomSheetDialog
的區別是支持更加豐富的BottomSheet屬性設置.
示例
佈局
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.jiuxing.bottomsheet.MainActivity" >
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" >
<Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Open" />
</LinearLayout>
<LinearLayout app:behavior_peekHeight="60dp" app:behavior_hideable="true" app:behavior_skipCollapsed="false" android:id="@+id/rl" android:layout_width="match_parent" android:layout_height="500dp" android:background="@color/colorPrimary" android:orientation="vertical" app:layout_behavior="@string/bottom_sheet_behavior" />
</android.support.design.widget.CoordinatorLayout>
複製代碼
代碼
public class MainActivity extends AppCompatActivity {
private BottomSheetBehavior<View> mBottomSheetBehavior;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.rl));
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
@OnClick(R.id.button) public void onClick() {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
複製代碼
方法
void setHideable (boolean hideable) // 是否可隱藏 void setPeekHeight (int peekHeight) // 摺疊高度, 即下拉時固定在屏幕下方的高度 void setSkipCollapsed (boolean skipCollapsed) // 不折疊, 徹底隱藏 void setState (int state) // 設置當前Behavior狀態 複製代碼
BottomSheetBehavior有五種狀態:
Tip: 某些狀態是過程當中狀態, 直接經過setState
去設置是無效的. 例如正在拖動狀態
屬性
android.support.design:behavior_hideable // 是否可所有隱藏, 默認false, 若是設置爲true則默認狀態爲隱藏
android.support.design:behavior_peekHeight // 最小摺疊高度
android.support.design:behavior_skipCollapsed // 若是爲true. 向下拖拽時直接隱藏而不是摺疊(hideable爲true方有效)
複製代碼
狀態變化回調
void setBottomSheetCallback (BottomSheetBehavior.BottomSheetCallback callback) 複製代碼
示例
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
/** * @param bottomSheet * @param newState 當前狀態 */
@Override public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
/** * @param bottomSheet * @param slideOffset 拖拽是座標偏移 */
@Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
})
複製代碼
特色介紹: