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) {
}
})
复制代码
特色介绍: