Android 撸起袖子,自己封装 DialogFragment

前言

具体的代码以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,欢迎 star 和 fork.

本文的主要内容

  • DialogFragment 是什么
  • 创建通用的 CommonDialogFragment
  • 实现各种类型的 DialogFragment

在写正文之前,先来一波效果展示吧
DialogFragmentDemos.gif

一、DialogFragment 是什么

DialogFragment 在 Android 3.0 时被引入,是一种特殊的 Fragment,用于在 Activity 的内容之上显示一个静态的对话框。例如:警告框、输入框、确认框等。

1、DialogFragment 的优点

其实在 Android 中显示对话框有两种类型可供使用,一种是 DialogFragment,而另一种则是 Dialog。在 DialogFragment 产生之前,我们创建对话框一般采用 Dialog,而且从代码的编写角度来看,Dialog 使用起来其实更加简单,但是 Google 却是推荐尽量使用 DialogFragment,是不是感觉很奇怪,其实原因也很简单, DialogFragment 有着 Dialog 所没有的非常好的特性

  • DialogFragment 本身是 Fragment 的子类,有着和 Fragment 基本一样的生命周期,使用 DialogFragment 来管理对话框,当旋转屏幕和按下后退键的时候可以更好的管理其生命周期
  • 在手机配置变化导致 Activity 需要重新创建时,例如旋转屏幕,基于 DialogFragment 的对话框将会由 FragmentManager 自动重建,然而基于 Dialog 实现的对话框却没有这样的能力

2、DialogFragment 的使用

使用 DialogFragment 至少需要实现 onCreateView() 或者 onCreateDialog() 方法,onCreateView() 即使用自定义的 xml 布局文件来展示 Dialog,而 onCreateDialog() 即使用 AlertDialog 或者 Dialog 创建出 我们想要的 Dialog,因为这篇文章主要是讲 DialogFragment 的封装,至于 DialogFragment 具体的使用,可以参考下洋神的这篇文章 Android 官方推荐 : DialogFragment 创建对话框

二、创建通用的 CommonDialogFragment

这个类是 DialogFragment 的子类,对 DialogFragment 进行封装,依赖外部传入的 AlertDialog 来构建,同时也处理了 DialogFragment 中 AlertDialog 不能设置外部取消的问题

public class CommonDialogFragment extends DialogFragment {/*** 监听弹出窗是否被取消*/private OnDialogCancelListener mCancelListener;/*** 回调获得需要显示的dialog*/private OnCallDialog mOnCallDialog;public interface OnDialogCancelListener {void onCancel();}public interface OnCallDialog {Dialog getDialog(Context context);}public static CommonDialogFragment newInstance(OnCallDialog call, boolean cancelable) {return newInstance(call, cancelable, null);}public static CommonDialogFragment newInstance(OnCallDialog call, boolean cancelable, OnDialogCancelListener cancelListener) {CommonDialogFragment instance = new CommonDialogFragment();instance.setCancelable(cancelable);instance.mCancelListener = cancelListener;instance.mOnCallDialog = call;return instance;}@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {if (null == mOnCallDialog) {super.onCreateDialog(savedInstanceState);}return mOnCallDialog.getDialog(getActivity());}@Overridepublic void onStart() {super.onStart();Dialog dialog = getDialog();if (dialog != null) {//在5.0以下的版本会出现白色背景边框,若在5.0以上设置则会造成文字部分的背景也变成透明if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {//目前只有这两个dialog会出现边框if(dialog instanceof ProgressDialog || dialog instanceof DatePickerDialog) {getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));}}Window window = getDialog().getWindow();WindowManager.LayoutParams windowParams = window.getAttributes();windowParams.dimAmount = 0.0f;window.setAttributes(windowParams);}}@Overridepublic void onCancel(DialogInterface dialog) {super.onCancel(dialog);if (mCancelListener != null) {mCancelListener.onCancel();}}}

可以看到这个类的代码量也是很少的,先定义了两个接口 OnDialogCancelListener,OnCallDialog,前者用于监听弹出窗是否被取消,后者则可以让我们回调获得想要显示的 Dialog,可以看到在 onCreateDialog() 中我们返回的 是 mOnCallDialog.getDialog(getActivity);,当我们在传入 Dialog 的时候,便会回调到此处,让 onCreateDialog() 返回我们传入的 Dialog,对接口回调不是很清楚的朋友,可以看下这篇文章 一个经典例子让你彻彻底底理解java回调机制

接着在 onStart() 中进行了一些特殊性的处理,因为在 5.0 以下的版本,ProgressDialog 和 DatePickerDialog 会出现白色的边框,这使得用户体验非常不好,所以我们要在此处进行相应的处理

最后便是封装我们的构造函数
newInstance(OnCallDialog call, boolean cancelable, OnDialogCancelListener cancelListener),当我们要使用这个 CommonDialogFragment 的时候,先 new 一个 OnCallDialog,将我们想要显示的 Dialog 传进去,cancelable,用于设置对话框是否能被取消,可以看到在 onCancel() 有这样一段代码

if(mCancelListener != null){mCancelListener.onCancel();
}

这便是我们在构造函数中传入 OnCancelListener 的原因,当我们想要做一些取消对话框后的处理时,只要在构造函数中传入 OnCancelListener,实现 onCancel() 方法就行了

三、实现各种类型的 DialogFragment

既然前面我们创建了 CommonFragment 作为所有 DialogFragment 的基类,那么接下来我们当然要好好地来实现各种类型的 DialogFragment 了,我的思路是创建一个 DialogFragmentHelper 作为实现提示框的帮助类,帮我们把代码都封装起来,使用的时候只需要关注与 AlertDialog 的交互,Helper 会帮助我们用 DialogFragment 来进行显示,这样既能统一整个应用的 Dialog 风格,又能让我们实现各种各样的对话框变得相当的简单

在实现 DialogFragmentHelper 之前我们有两件事先要做一下

1、在 styles 文件中定义我们定义我们对话框的风格样式
<style name="Base_AlertDialog" parent="Base.Theme.AppCompat.Light.Dialog"><!--不设置在6.0以上会出现,宽度不充满屏幕的情况--><item name="windowMinWidthMinor">90%</item><!-- 取消标题栏,如果在代码中settitle的话会无效 --><item name="android:windowNoTitle">true</item><!-- 标题的和Message的文字颜色 --><!--<item name="android:textColorPrimary">@color/black</item>--><!-- 修改顶部标题背景颜色,具体颜色自己定,可以是图片 --><item name="android:topDark">@color/app_main_color_deep</item><!--<item name="android:background">@color/white</item>--><!-- 在某些系统上面设置背景颜色之后出现奇怪的背景,处这里设置背景为透明,为了隐藏边框 --><!--<item name="android:windowBackground">@android:color/transparent</item>--><!--<item name="android:windowFrame">@null</item>--><!-- 进入和退出动画,左进右出(系统自带) --><!--<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>--><!-- 按钮字体颜色,全部一起改,单个改需要在Java代码中修改 --><item name="colorAccent">@color/app_main_color</item></style>

我已经打上了详细的注释,相信应该很容易理解

2、写一个接口,用于 DialogFragmentHelper 与逻辑层之间进行数据监听
public interface IDialogResultListener<T> {void onDataResult(T result);
}

准备工作做完了,就让我们开工撸 DialogFragmentHelper 吧,因为篇幅有限,我只是代表性的选了其中的一些效果来讲,具体的代码,可以参考下 DialogFragmentDemos

public class DialogFragmentHelper {private static final String TAG_HEAD = DialogFragmentHelper.class.getSimpleName();/*** 加载中的弹出窗*/private static final int PROGRESS_THEME = R.style.Base_AlertDialog;private static final String PROGRESS_TAG = TAG_HEAD + ":progress";public static CommonDialogFragment showProgress(FragmentManager fragmentManager, String message){return showProgress(fragmentManager, message, true, null);}public static CommonDialogFragment showProgress(FragmentManager fragmentManager, String message, boolean cancelable){return showProgress(fragmentManager, message, cancelable, null);}public static CommonDialogFragment showProgress(FragmentManager fragmentManager, final String message, boolean cancelable, CommonDialogFragment.OnDialogCancelListener cancelListener){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {ProgressDialog progressDialog = new ProgressDialog(context, PROGRESS_THEME);progressDialog.setMessage(message);return progressDialog;}}, cancelable, cancelListener);dialogFragment.show(fragmentManager, PROGRESS_TAG);return dialogFragment;}/*** 带输入框的弹出窗*/private static final int INSERT_THEME = R.style.Base_AlertDialog;private static final String INSERT_TAG  = TAG_HEAD + ":insert";public static void showInsertDialog(FragmentManager manager, final String title, final IDialogResultListener<String> resultListener, final boolean cancelable){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {// ...AlertDialog.Builder builder = new AlertDialog.Builder(context, INSERT_THEME);builder.setPositiveButton(DIALOG_POSITIVE, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if(resultListener != null){resultListener.onDataResult(editText.getText().toString());}}});builder.setNegativeButton(DIALOG_NEGATIVE, null);return builder.create();}}, cancelable, null);dialogFragment.show(manager, INSERT_TAG);}
}

可以看到因为我们实现封装了 CommonFragment,所有这些效果的实现都变得相当的简单吗,这便是封装给我们带来的便利和好处。

就以 加载中的弹出窗 为例,来看看我们是怎么实现的

    public static CommonDialogFragment showProgress(FragmentManager fragmentManager, final String message, boolean cancelable, CommonDialogFragment.OnDialogCancelListener cancelListener){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {ProgressDialog progressDialog = new ProgressDialog(context, PROGRESS_THEME);progressDialog.setMessage(message);return progressDialog;}}, cancelable, cancelListener);dialogFragment.show(fragmentManager, PROGRESS_TAG);return dialogFragment;}

我们先调用了 CommonDialogFragment 的构造函数,将一个 ProgressDialog 传进去,然后依次传入 cancelable 和 cancelListener,最后调用 show() 函数,将DialogFragment 显示出来,因为我们使用了构造函数的重载,可以看到最简单的构造函数只需要传入两个参数就行了,是不是相当的简洁啊。

应该还没忘了我们上面创建了一个 IDialogResultListener&lt;T&gt; 用于 DialogFragment 与逻辑层之间进行数据监听吧,为了能传入各种各样类型的数据,这里我使用了 泛型 来进行处理,就以 带输入框的弹出窗 为例来看看究竟要怎么使用吧

    public static void showInsertDialog(FragmentManager manager, final String title, final IDialogResultListener<String> resultListener, final boolean cancelable){CommonDialogFragment dialogFragment = CommonDialogFragment.newInstance(new CommonDialogFragment.OnCallDialog() {@Overridepublic Dialog getDialog(Context context) {// ... 这里省略一部分代码AlertDialog.Builder builder = new AlertDialog.Builder(context, INSERT_THEME);builder.setPositiveButton(DIALOG_POSITIVE, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {if(resultListener != null){resultListener.onDataResult(editText.getText().toString());}}});builder.setNegativeButton(DIALOG_NEGATIVE, null);return builder.create();}}, cancelable, null);dialogFragment.show(manager, INSERT_TAG);}

可以看到我们在 showInsertDialog() 方法中传入了IDialogResultListener&lt;String&gt; resultListener,当我们想要处理输入的内容的时候,只要在外部调用的时候,new 一个IDialogResultListener 传进去,然后实现 onDataResult() 方法就行了

以上便是全文的内容,具体的代码以及示例我都放上 Github 了,有需要的朋友可以去看一下 DialogFragmentDemos,如果觉得对你有所帮助的话,就赏个 star 吧!


猜你喜欢

  • 手把手教你从零开始做一个好看的 APP
  • Android 能让你少走弯路的干货整理
  • Android 一款十分简洁、优雅的日记 APP

转载于:https://blog.51cto.com/11365063/2072445

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

as模拟器文件夹路径_EGG Switch手机模拟器怎么用?中文教程来了......

大家好&#xff0c;小鸡妹我又来啦。自从昨天曝光了美国NX工作室的EGG模拟器之后&#xff0c;推文底下就多了一千多条留言&#xff0c;说啥的都有。不过小鸡妹大概总结了一下&#xff0c;发现下面这几条问题&#xff0c;出现的频率最高&#xff1a;① 找不到网址&#xff1b;②…

郁金香汇编代码注入怎么写看雪_世界黑客编程大赛冠军的汇编代码 你见过吗?...

前几天发布了一篇“雷军22年前写的汇编代码”的文章&#xff0c;引起网友的热议。有人说汇编是最牛逼的编程语言&#xff0c;没有之一。汇编语言确实厉害&#xff0c;不知道你有没有见过世界黑客编程大赛冠军的作品?雷军编写的的汇编代码有 网友分享了97年Mekka ’97 4K Intro…

变位齿轮重合度计算公式_齿轮“模数”是如何计算的?

模数是决定齿轮大小的因素。齿轮模数被定义为模数制轮齿的一个基本参数&#xff0c;是人为抽象出来用以度量轮齿规模的数。目的是标准化齿轮刀具&#xff0c;减少成本。直齿、斜齿和圆锥齿齿轮的模数皆可参考标准模数系列表。工业定义&#xff1a;齿轮的分度圆是设计、计算齿轮…

获取freemarker处理后的内容

相信很多人都用过freemarker&#xff0c;或做视图&#xff0c;或模板&#xff0c;或生成静态文件等,但是有多少人做过这样的应用&#xff0c;通过模板后&#xff0c;不是要输出静态的内容&#xff0c;而是直接在代码中获取处理模板后的内容&#xff0c;研究了下API,freemarker里…

c4.5算法python实现_算法:用Python实现—最优化算法

今天给大家分享一下算法&#xff0c;用python来实现最优化算法。废话不多说&#xff0c;直接上代码&#xff1a;一、二分法函数详见rres&#xff0c;此代码使该算法运行了两次def asdf(x): rres8*x**3-2*x**2-7*x3 return rresi2left0right1while i>0 : i i-1 …

vs怎么更改编译的堆空间_再见吧 buildSrc, 拥抱 Composing builds 提升 Android 编译速度...

前言长期以来困扰我们的一个问题就是构建速度&#xff0c;AndroidStudio 的构建速度严重影响 Android 开发者的工作效率&#xff0c;尤其是更新一个版本号&#xff0c;导致整个项目重新构建&#xff0c;在网络慢的情况下&#xff0c;这是无法忍受的。buildSrc 这种方式&#xf…

java map的遍历

转载地址&#xff1a;http://www.cnblogs.com/shenliang123/archive/2012/08/28/2660705.html -------------------------------------------------------------------------------------------------------------------- java中的遍历 import java.util.Collection; import j…

android悬浮功能实现,Android实现系统级悬浮按钮

本文实例为大家分享了Android系统级悬浮按钮的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下具体的需求1、就是做一个系统级的悬浮按钮&#xff0c;就像iPhone 桌面的那个悬浮按钮效果一样&#xff0c;能随意拖动&#xff0c;并且手一放开&#xff0c;悬浮按钮就自动…

oracle decode_错过血亏!一文搞懂Oracle锁相关视图及相关操作

本文主要研究锁的相关视图&#xff0c;以及锁的相关操作&#xff0c;通过视图查锁的问题。 一、v$transaction视图第一个视图是v$transaction&#xff0c;就是Oracle数据库所有活动的事务数&#xff0c;所有活动的事务每一个活动的事务在这里有一行。v$transactionXIDUSN表示当…

Linux文件系统与命令行

什么是命令行? 接收键盘命令并将其传给操作系统执行的程序(用于输入和管理命令的程序),统称命令行,也叫: Shell&#xff0c;几乎所有Linux发行版都提供了一个 Shell 程序,叫做: Bash (Bourne-Again Shell, 因为最初的 Shell 是由 Steve Bourne 编写的原始 Unix 程序, Again 表…

android 自定义菜单栏,GitHub - earthWo/AndroidBottomNavigation: android 底部菜单栏,自定义样式,自定义菜单数量,添加滚动动画和水波纹动画...

AndroidBottomNavigation截图使用方法gradle:compile com.whitelife.library:library:1.0.1maven:com.whitelife.librarylibrary1.0pomandroid:id"id/bottom_navigation"android:layout_width"match_parent"android:layout_height"56dp"android:…

windows怎么打开python_windows怎么打开Python

Windows中运行Python的两种运行方式认识编程环境 1 直接命令行启用Python。当然&#xff0c;如果直接在cmd中输入python&#xff0c;需要在windows中的path环境变量中做好设置。 此时&#xff0c;cmd中运行python就可以出现 “>>>” 符号。意味着python进入了交互运行…

AOE网与关键路径简介

前面我们说过的拓扑排序主要是为解决一个工程能否顺序进行的问题&#xff0c;但有时我们还需要解决工程完成需要的最短时间问题。如果我们要对一个流程图获得最短时间&#xff0c;就必须要分析它们的拓扑关系&#xff0c;并且找到当中最关键的流程&#xff0c;这个流程的时间就…

Java 集合体系详解——List体系有序集合

引言 面向对象语言对事物的体现必然是以对象的形式&#xff0c;Java工程师为了方便多多个对象的操作&#xff0c;就对对象进行存储&#xff0c;集合就是存储对象的一种方式&#xff0c;他们的底层都是基于不同的数据结构。当然集合和数组一样都是容器&#xff0c;数组也是可以存…

alert闪一下就没了_尾部贯穿式镀铬银饰条除了丑,还能闪瞎眼

尾部贯穿式镀铬银饰条&#xff0c;在2010年代成为诸多汽车品牌车型争相采用的新世纪新标配&#xff0c;配以双边排气&#xff0c;让整个车尾看起来层次感强烈&#xff0c;视觉收窄&#xff0c;几十万的奥迪A8L有&#xff0c;十几万的斯柯达速派有&#xff0c;A级车有&#xff0…

docker 指定网卡_Docker | Docker技术基础梳理(五) Docker网络管理

为什么需要容器的网络管理&#xff1f;容器的网络默认与宿主机、与其他容器相互隔离&#xff0c;且容器中可以运行一些网络应用&#xff0c;比如nginx、web应用、数据库等&#xff0c;如果需要让外部也可以访问这些容器中运行的网络应用&#xff0c;那么就需要配置网络来实现。…

Android安装两次才成功,Android应用从市场安装完成打开与桌面打开,被启动两次的问题...

问题描述&#xff1a;1、从Android应用市场下载并安装应用&#xff0c;安装完成后&#xff0c;当前界面下方会出现“打开”按钮&#xff0c;这时候我们点击“打开”&#xff0c;会启动应用&#xff0c;进入到应用的启动页面&#xff0c;然后进入应用的主界面&#xff0c;这个时…

事务保存点

在SQL Server中使用rollback会回滚所有的未提交事务状态&#xff0c;但是有些时候我们只需要回滚部分语句&#xff0c;把不需要回滚的语句提到事务外面来&#xff0c;虽然是个方法&#xff0c;但是却破坏了事务的ACID。 SQL中使用事务保存点 即可解决这个问题. 一.SQL 事务中存…

鼎信诺审计前端取数工具_给2019前端的5个建议

2019 农历新年即将到来&#xff0c;是时候总结一下团队过去一年的技术沉淀。过去一年我们支撑的数据相关业务突飞猛进&#xff0c;其中两个核心平台级产品代码量分别达到30万行和80万行&#xff0c;TS 模块数均超过1000个&#xff0c;协同开发人员增加到20人。由于历史原因&…

Hadoop HA

HA概念&#xff1a; high avalability 高可用性。 hadoop 1.x非ha设计 Secondnode对元数据的可靠性有了保障&#xff0c;但服务的可用性不高。 即&#xff1a;当Namenode节点宕机了&#xff0c;整个hadoop就不能使用了&#xff0c;影响了client的使用。 hadoop 2.x的ha设计 新…