在Android开发中,我们在很多情况下都会使用到Dialog,即弹出框。如弹出一个登录框,又如有操作需要用户二次确认等情况。本片文章就来阐述一下如何在Android开发过程中,正确的使用Dialog。

Dialog的设计哲学

Dialog是一个弹出框,小的窗口,用来提示用户确认下一步的操作(在确认前这个操作并不执行)或展示额外信息(如下一步的必然操作中确实需要用户知道的信息)。既然是弹出框,就不应该充满全屏(一般情况下),并且要尽可能简短精悍的表达想要展示给用户的意思,剔除一切冗余信息。下图展示了一个标准的Dialog:

1. 标题栏。

用来介绍这个Dialog用来干什么,比如形容自己是在请求用户做什么,或是应用所请求的是什么内容。标题的展现形式可以是单一的文字,也可以是图标+文字。

官方的建议是Dialog如果就是用来警示用户,那么完全可以不需要标题,直接显示内容告诉用户即将发生重要的事情。而有些对于用户来说特别重要的事项,比如丢失数据、产生运营商流量、消费动作等则最好是用最直接的话做标题,然后在内容中做清晰表述。打个比方,如果产生了消费动作,标题就可以起“结账”,内容用来详细表明结的什么账,明细是什么。最好不要在起“警告”这样的标题,因为完全可以用代表警告的图标来表达。

2. 内容。

Dialog主要展示的就是内容了,可以展示多种类型的内容,比如一段重要的描述性话语,或如图中展示的一样是一些单选,同时也可以是多选列表,甚至可以是开发者自定义的任何视图。最需要注意的就是对内容详细或简略的程度进行把控,如果内容过少,那么可以考虑通过交互方式的修改来使用Toast进行展示,毕竟Dialog会阻挡用户的操作,内容较少的Dialog可能会让用户感觉不疼不痒,甚至认为这个提示并不重要,从而降低应用本身的用户体验或者是误操作。

顺便提一下题外话,前一阵子网上爆出的Android最可怕病毒(自动发送短信,传播自身)其实就是滥用Android权限的结果。可见,如果在一些重要动作上不对用户进行必要的提醒、提示,那么某种角度上讲这个应用与“病毒”差不多。

3. 动作按钮

最多两个按钮,一个确定、一个取消,像上图中内容为单选列表,那么就可以理解为点击内容即为“确定”,所以“取消”按钮就不需要了,甚至当Dialog允许通过返回按键或点击Dialog外的区域进行取消时,“取消”按钮也不需要。也就是说,动作按钮这里,可以是2,可以是1,也可以是无。具体的设计逻辑根据Dialog的具体作用决定,如果只是单单的提示,叫用户知道某些信息而已,那么完全可以只放一个“我知道了”按钮,其实这个按钮是“取消”的动作。

对于动作按钮区域并没有什么需要格外注意的,唯一能想到的也就是Android在4.0后将“确定”、“取消”的左右位置换为“确定“在右,”取消“在左。如果一意孤行非要跟主流不一样的话,我想也只能用”呵呵“进行回应了。毕竟是有”用户习惯“这么个名词存在的,当大家都已经习惯了一套规则的时候,所谓”悖论创新“可能也只是”顽皮任性“的挡箭牌而已。

Toast

Dialog算是一个重度的弹出框,在描述”内容“的设计哲学时也说过,如果说内容过少,又只是想提示用户而非叫用户做选择、决定时完全可以考虑使用更加轻量级、对用户体验影响偏小的Toast进行提示。在用户操作上,Toast相比Dialog更加友好,因为Toast在一段时间(Android默认长则3.5秒,短则2秒)后会自动消失,而Dialog必须需要用户进行干涉才可以消失。同时,Toast并不会影响用户在界面上的下一步操作,而Dialog属于一种打断行为,不进行处理就甭想进行下一步操作。信不信由你,如果一个应用能够做到连续弹出3个以上Dialog,用户不是摔手机就一定是卸载应用了。

Dialog的初级开发使用

Android官方建议不要直接使用Dialog这个类来构造应用的弹出框,在开发实践中也很容易发觉确实使用Dialog直接构造弹出框并不方便,基本的视图框架都需要自己来进行设计规划,对于一个简简单单的弹出框来说,这样的实现复杂度明显不符合开发预期。而遵循官方的建议,我们通常使用AlertDialog进行弹出框的构造,同时对于开发过程中可能出现的日期、时间的选择窗口,Android官方也早有准备,分别是DatePickerDialog和TimePickerDialog。(推荐一个开源项目,界面更加友好美观https://github.com/flavienlaurent/datetimepicker)

另,不得不在此提及Android所提供的另一个Dialog,即ProgressDialog。这个Dialog类型是Android官方不建议使用的,原话是:避免使用ProgressDialog。从开发角度上讲,ProgressDialog的使用极其简单,并没有很高的门槛。Android官方这样建议更多是出于设计和用户体验方面的考虑。ProgressDialog的弹出在屏幕上占用了非常小的空间,其他区域罩以灰色蒙板。并且通常情况下ProgressDialog还需要阻挡用户下一步操作,直到其所等待的事件完成为止。即使不考虑可能发生的设备旋转情况,ProgressDialog的单一、阻挡性强、视图不友好这几方面就足以导致用户的不舒适感。所以,在设计、开发过程中,遇到需要用户等待的情况,建议以视图布局中嵌入ProgressBar代替,这样的原因有:

一、整个屏幕不会罩以灰色蒙板,相信很多用户并不喜欢这样的东西;

二、ProgressBar并不会阻挡用户在屏幕上的全部操作。即使ProgressBar在显示中,也不会影响例如NavigationDrawer控件的使用。

三、在开发中,ProgressDialog对于旋转的处理要难于ProgressBar。因此容易出现疏忽,造成用户的混淆或误操作。

下边直接介绍关于AlertDialog的使用明细。

AlertDialog使用示例:

[java] view plaincopy print?
  1. AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
  2. AlertDialog.THEME_DEVICE_DEFAULT_DARK);
  3. builder.setTitle("Dialog title")
  4. .setIcon(android.R.drawable.stat_sys_warning)
  5. .setMessage("Dialog content")
  6. .setPositiveButton("OK", null)
  7. .setNegativeButton("Cancel", null);
  8. builder.create().show();

效果图:

使用AlertDialog构造弹出框都是通过Builder构造器进行构造,除了设置三大视觉结构相关设置外,还可以设置是否可以取消(通过返回按钮)。两种方法:

第一种是在AlertDialog.Builder构造时调用

[java] view plaincopy print?
  1. setCancelable(boolean cancelable)

第二种通过调用AlertDialog.Builder create生成的Dialog同样的接口。

还可以设置在用户点击弹出框以外的视图区域时是否让弹出框消失,通过调用生成的Dialog的接口:

[java] view plaincopy print?
  1. setCanceledOnTouchOutside(boolean cancel)

以上两个默认都是false。

1.  需要显示列表

调用AlertDialog.Builder的接口。

[java] view plaincopy print?
  1. setAdapter(ListAdapter adapter, DialogInterface.OnClickListener listener)

adapter参数即为ListView的Adapter, 用来确定列表的视图。

listener参数为列表项的点击监听器。

视觉效果如:

这时并不需要”确认“与”取消“按钮,直接点击列表项即视为选择。

2. 需要显示单选列表

形如:

实现代码为:

[java] view plaincopy print?
  1. AlertDialog.Builder builder = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK);
  2. builder.setTitle("Choose ringtone")
  3. .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
  4. @Override
  5. public void onClick(DialogInterface dialog, int which) {
  6. //Handle ok event
  7. }
  8. })
  9. .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
  10. @Override
  11. public void onClick(DialogInterface dialog, int which) {
  12. //Handle cancel event
  13. }
  14. })
  15. .setSingleChoiceItems(ringtones, 0, new DialogInterface.OnClickListener() {
  16. @Override
  17. public void onClick(DialogInterface dialog, int which) {
  18. //Handle item click event
  19. }
  20. });
  21. builder.create().show();

AlertDialog.Builder的setSingleChoiceItems接口,形式共有四种:

第一种:

[java] view plaincopy print?
  1. setSingleChoiceItems(CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener)

items参数为列表中显示的字符;

checkedItem 因为列表是单选,一般是有一个默认就选中的项目,这个参数就用来指定第几个项目是默认被选中的,从0起。若为-1则代表没有默认选择;

listener参数就是列表项点击监听器。

这种方式适合选项只是简单的字符。

第二种:

[java] view plaincopy print?
  1. setSingleChoiceItems(int itemsId, int checkedItem, DialogInterface.OnClickListener listener)

itemsId 参数为指定xml中事先定义好的String array。其他参数意义同第一种。

第三种:

[java] view plaincopy print?
  1. setSingleChoiceItems(ListAdapter adapter, int checkedItem, DialogInterface.OnClickListener listener)

adapter参数为列表的Adapter,用来决定每个列表项的视觉效果

checkedItem和listener的意义同第一种方式中一样。

这种方式适合选项的视图复杂的需求。

第四种:

[java] view plaincopy print?
  1. setSingleChoiceItems (Cursor cursor, int checkedItem, String labelColumn, DialogInterface.OnClickListener listener)

cursor为列表中项目数据所在的数据库Cursor

labelColumn参数为需要展示的数据在数据库中的列名是什么

其他参数与另三种方法无异。

再次提一下在单选项弹出框中动作按钮是否需要展现的问题。建议同时展现”确定“和”取消“按钮。

展现”确认“按钮的原因是在实际使用过程中,用户极有可能轮流点击不同的选项,若开发者视为点击选项就是确定,那么这样用户需要做的重复动作就比较多。用户可能有这样的行为是因为:

一、手指的习惯动作;

二、想要通过选择不同选项直接看到结果,如更换主题(想要看到更换后的直接效果,哪一个符合就选择确定)。

而展现“取消”按钮的原因是:

一、因为弹出框可以对本身是否能够通过点击外部区域进行取消做设置,假设用户使用了多款对各自弹出框进行了不同设置的应用,那么极有可能已经混淆了究竟是否可以通过点击外部区域进行弹出框的取消,所以这个时候直接提供一个“取消”按钮就能够解决用户的疑虑,正如Android设计规范中所说,不要让用户去想,而是提供给用户最直接的选项让他选择,这样做才是较好的用户体验。

二、即使手机的返回按键可以取消弹出框,大多数情况下用户手指从弹出框移动到返回键的距离还是不小的,而且如果是单手操作,这样也可能产生手机滑落的情况发生,最糟的用户体验也莫过于此了。所以,提供一个“取消”按钮,大多数情况下,用户直接点击“取消”来取消弹出框显然更方便、更安全。

3. 需要显示多选列表

形如:

以下代码实现了上图中的Dialog:

[java] view plaincopy print?
  1. AlertDialog.Builder builder = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_LIGHT);
  2. builder.setTitle("Pick your toppings")
  3. .setMultiChoiceItems(new String[]{"Onion", "Lettuce", "Tomato"},
  4. new boolean[]{false, true, true},
  5. new DialogInterface.OnMultiChoiceClickListener() {
  6. @Override
  7. public void onClick(DialogInterface dialog, int which, boolean isChecked) {
  8. //Handle item click event
  9. }
  10. })
  11. .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
  12. @Override
  13. public void onClick(DialogInterface dialog, int which) {
  14. // Handle ok event
  15. }
  16. })
  17. .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
  18. @Override
  19. public void onClick(DialogInterface dialog, int which) {
  20. // Handle cancel event
  21. }
  22. });
  23. builder.create().show();

AlertDIalog.Builder的setMultiChoiceItems方法,有三种形式:

第一种:

[java] view plaincopy print?
  1. setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)

items参数与单选中的意义一样,是所有项目的字符集合;

checkedItems参数为哪些选项是默认选中的。需要注意的是,如果是null就代表没有默认选中的,而如果是非null,那么长度必须要和items一样。

listener参数为表内项目点击监听器。

第二种:

[java] view plaincopy print?
  1. setMultiChoiceItems(int itemsId, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)

itemsId参数将需要显示的所有项目指定到事先定义好的String array上。其他参数与第一种无异。

第三种:

[java] view plaincopy print?
  1. setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, DialogInterface.OnMultiChoiceClickListener listener)

cursor参数为需要显示的项目所在数据库Cursor

labalColumn为项目数据所在数据库中的列名

其他参数与其他方法无异。

到这里可以发现,包含多选列表的弹出框中,并没有通过指定Adapter构造的方法,看似是一种缺失。而联系实际使用,不难发现,复杂视图的多选项弹出框鲜有。我本人是想不到究竟有什么场景需要复杂视图的、多选项的——弹出框。当然,如果一定有这种需求要实现,可完全可以通过自定义视图的弹出框实现(稍后做介绍)。

4. 需要自定视图

自定义视图,指的是自定义Dialog的“内容”区域视图,通过API setView(View view)实现。实现过程也非常简单,可以实现设计好一套布局,然后通过LayoutInflater产出一个View,将这个View设置进去。如果在这个View(“内容”自定义视图)中,需要做必要的监听,同样通过findViewById方法得到需要监听的对象做相应处理即可。

PS:不对AlertDialog.Builder设置Title,最终的Dialog就不会有Title视图。

Dialog开发进阶

通过以上的介绍,相信在对Dialog的使用上起码视图的需求都应该没有问题了。接下来还有一些实际开发过程中的问题需要处理。如:设备发生旋转,上面所做的这些Dialog会发生什么?答案是他们会消失。为什么消失?以开发过程中最熟悉的Activity为例,若设备发生旋转,Activity会先销毁onDestroy,再恢复onCreate,同时相关必要数据的恢复可以通过Bundle进行。而上边所做的这些Dialog并不能处理自己的生命周期,一旦设备发生旋转,会立即由系统dismiss掉。通过引入DialogFragment,使其作为AlertDialog的载体可以完美解决这个问题。

DialogFragment继承于Fragment,专门用来做Dialog的承载体,类似设备旋转这样的事件DialogFragment自然就有了能力去处理,其中的Dialog也不至于被系统直接dismiss掉。

实现一个DialogFragment非常简单,只要实现onCreateDialog方法即可,其原型为:

[java] view plaincopy print?
  1. public Dialog onCreateDialog(Bundle savedInstanceState) {
  2. return new Dialog(getActivity(), getTheme());
  3. }

通过直接返回一个Dialog对象即可实现,所以上边实现的第一个AlertDialog就可以转换为:

[java] view plaincopy print?
  1. public Dialog onCreateDialog(Bundle savedInstanceState) {
  2. AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
  3. AlertDialog.THEME_DEVICE_DEFAULT_DARK);
  4. builder.setTitle("Dialog title")
  5. .setIcon(android.R.drawable.stat_sys_warning)
  6. .setMessage("Dialog content")
  7. .setPositiveButton("OK", null)
  8. .setNegativeButton("Cancel", null);
  9. return builder.create()
  10. }

光是这样Dialog还没有显示出来,像普通的Dialog一样,需要一个show方法的触发,不过通过DialogFragment实现的Dialog的show方法有些不同:

[java] view plaincopy print?
  1. public void show(FragmentManager manager, String tag)
  2. public int show(FragmentTransaction transaction, String tag)

不要忘了DialogFragment是继承于Fragment的,要显示他必然需要用到FragmentManager或FragmentTransaction。这里提醒一下,如果是Fragment中调用DialogFragment,在show的时候需要注意使用的是getChildFragmentManager,这样能保证正确的Fragment层级关系。

通过上边对DialogFragment的引入,达到了旋转设备Dialog不消失的效果。但是如果Dialog内容中有状态变动,旋转后会被复位,其实这个问题就是要解决Fragment的旋转屏幕问题。通过onSaveInstanceState与onCreateDialog的配合很好做到这一点。这里不再赘述。

最后,强烈提示!!!实现自己的DialogFragment一定要保留默认构造函数,即空的、public的构造函数,否则会产生程序异常。

总结

本篇文章完整、详尽的从设计到开发介绍了Android系统中关于Dialog的使用详情。本质上,Dialog的使用非常简单,更多的则是关于应用、产品质量与用户体验的追求。无论是移动互联网狂潮也好,还是传统企业也好,质量、用户体验都是需要与时俱进的。·

Android应用开发:Dialog使用及示例相关推荐

  1. 【Android FFMPEG 开发】C++ 回调 Java 方法 模板 ( JavaVM *vm | JNIEnv *env | jobject instance | 引用类型 | 模板代码示例 )

    文章目录 I . Native 调用 Java 方法 II . JNIEnv *env 与 jobject instance III . JavaVM *vm IV . 局部引用 与 全局引用 分析 ...

  2. Android游戏开发系统控件-Dialog

    Android游戏开发系统控件-Dialog Dialog(对话框)在Android应用开发中经常用到,下面是学习<Android游戏编程从零开始>一书,关于Dialog的初步学习. 创建 ...

  3. Android软件开发之盘点所有Dialog对话框大合集(一)

    转:http://xys289187120.blog.51cto.com/3361352/657562/ 雨松MOMO带大家盘点Android 中的对话框 今天我用自己写的一个Demo 和大家详细介绍 ...

  4. 【Android 应用开发】Android 无障碍开发简介 ( Android 无障碍开发辅助技术 | 启用 TalkBack 无障碍功能 | TalkBack 无障碍开发 示例 )

    文章目录 一.Android 无障碍开发辅助技术 二.启用 TalkBack 无障碍功能 三.TalkBack 无障碍功能代码示例 官方文档 : Android 无障碍功能概览 一.Android 无 ...

  5. SuperMap iMobile+Android studio开发入门(二)——超图示例代码运行

    背景:这里运行的是"产品入门"的"基于Android studio开发移动GIS程序"的"开发三维移动GIS程序",本篇对超图帮助文档进行了 ...

  6. nfc读卡java开发,Android通过NFC读取IC卡示例

    [实例简介] Android通过NFC读取IC卡示例,包含读取.写入. [实例截图] [核心代码] nfc_demo └── nfc_demo ├── app │   ├── app.iml │   ...

  7. Android开发——Dialog对话框

    AlertDialog 消息提示机制,常用来向用户传递信息.提示或警告用户行为的. 常用方法:setTitle.setMessage.create.show package com.example.d ...

  8. android蓝牙开发代码,Android蓝牙开发(示例代码)

    Android蓝牙开发 近期做蓝牙小车,须要Android端来控制小车的运动.以此文记录开发过程. 使用HC-06无线蓝牙串口透传模块.对于其它的蓝牙设备本文相同适用. 蓝牙开发的流程: 获取本地蓝牙 ...

  9. Android应用开发:数据存储和界面展现-2

    1. pull解析XML文件 Android推荐使用pull解析XML文件,与SAX解析XML文件类似,都是事件驱动类型的解析方式. 示例:获取天气信息 res\layout\activity_mai ...

  10. Android应用开发:数据存储和界面展现-1

    1. 相对布局RelativeLayout 特点:相对布局所有组件可以叠加在一起:各个组件的布局是独立的,互不影响:所有组件的默认位置都是在左上角(顶部.左部对齐) 属性 功能描述 android:l ...

最新文章

  1. Mysql 安装及实践(学习笔记二)
  2. Nature综述:植物与微生物组的相互作用:从群落装配到植物健康(下)
  3. vue循环渲染变量类样式
  4. Faster R-CNN论文详解
  5. 优先级反转和解决方法
  6. linux命令行变大,Linux命令行下'!'的8大神奇的用法!
  7. 17款加速效率的CSS工具
  8. devexpress java_DevExpress使用心得一:换肤
  9. 学习网站(不断更新)
  10. 刀片服务器改台式电脑_服务器到底是个什么东东?跟电脑有啥区别?电脑知识学习!...
  11. 基于AS3的水果机小游戏
  12. [Cocos2d-x] init()和onEnter()方法的区别
  13. magento yandex插件 moneta插件 qiwi插件 俄罗斯银行
  14. 信号硬件入门--振幅调制信号发生器(正弦波发生器方案、AM调制方案)--First理论部分
  15. 如何清理苹果MAC电脑系统缓存数据?
  16. PDF 文字识别网站
  17. 高德地图定位,搜索,导航功能
  18. 决策树分析例题经典案例_决策树例题经典案例280_决策树在产品满意因素分析中的应用...
  19. 如何让孩子算20以内的加法更快
  20. Crosswalk 运行报错问题

热门文章

  1. 【Android LibGDX游戏引擎开发教程】第06期:图形图像的绘制(下)图片整合工具的使用...
  2. ASPack 2.x (without poly) - Alexey Solodovnikov [Overlay]脱壳
  3. instanceof和typeof
  4. 路长全讲座免费在线学习 免费下载
  5. vue项目中返回按钮案例(用vuex控制返回按钮的显示或者隐藏)
  6. houghlinesp找到多条直线_拿什么拯救焦虑的你,一个有勇气的人终将找到他的路...
  7. onenote快捷键_onenote快捷键的高效用法
  8. Oracle的权限角色及用户
  9. 迭代器:斐波那契数列
  10. 十六进制转为float,float转为二进制