前言

本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍:

我的 GIthub 博客

思维导图

一、为什么要学习 DialogFragment

你还在用 Dialog 吗?

你还在经常烦恼于屏幕翻转的时候,Dialog 的各种奇葩情况吗?

你想降低耦合吗?

如果你有其中的一个烦恼,那么恭喜你,遇见了 DialogFragment ,他恰巧就解决了上面所说的问题,如果感兴趣的话,随笔者来看下吧!

二、背景

Android 官方推荐使用 DialogFragment 来代替 Dialog ,可以让它具有更高的可复用性(降低耦合)和更好的便利性(很好的处理屏幕翻转的情况)。

而创建 DialogFragment 有两种方式:

  • 法一:覆写其 onCreateDialog 方法

一般用于创建替代传统Dialog 对话框的场景,UI 简单功能单一,不适用于使用了多线程(例如网络请求)的情况下(因为不能正确的获取当前 Fragment 的状态,会产生空指针异常)

  • 法二:覆写其 onCreateView 方法

一般用于创建复杂内容弹窗全屏展示效果的场景,UI 复杂功能复杂一般有网络请求等异步操作

三、应用

3.1 基本用法是什么

法一:

a.创建一个简单的 Dialog 并返回它即可

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 设置主题的构造方法
// AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.CustomDialog);
builder.setTitle("注意:")
.setMessage("是否退出应用?")
.setPositiveButton("确定", null)
.setNegativeButton("取消", null)
.setCancelable(false);
//builder.show(); // 不能在这里使用 show() 方法
return builder.create();
}

运行截图

b.你也可以使用自定义 View 来创建:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 设置主题的构造方法
// AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.CustomDialog);
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
builder.setView(view)
// Do Someting,eg: TextView tv = view.findViewById(R.id.tv);
return builder.create();
}

运行截图

PS:创建 Dialog 的方式有多种,比如下面这种,使用时略有差异,需要自己注意:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
Dialog dialog = new Dialog(getActivity());
// 设置主题的构造方法
// Dialog dialog = new Dialog(getActivity(), R.style.CustomDialog);
dialog.setContentView(view);
// Do Someting
return dialog;
}

运行截图

这种情况,标题内容上面的白色部分,其实是默认的标题栏,如果需要的话,可以设置隐藏标题栏(将在下文说到)

3.2 如何处理屏幕翻转

如果使用传统的 Dialog ,需要我们手动处理屏幕翻转的情况,但使用 DialogFragment 的话,则不需要我们进行任何处理,FragmentManager 会自动管理 DialogFragment 的生命周期。

3.3 如何隐藏标题栏

在基本用法里代码注释有设置主题的地方,下面详细说下两种方法下设置无标题栏的方式:

法一:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = Objects.requireNonNull(getActivity()).getLayoutInflater();
@SuppressLint("InflateParams") View view = inflater.inflate(R.layout.fragment_i_o_s_dialog, null);
Dialog dialog = new Dialog(getActivity());
// 关闭标题栏,setContentView() 之前调用
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}

法二:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, 0);
}

3.4 如何实现全屏

常用的形式大多是宽度上和屏幕一样宽,高度自适应,下面直接看代码:

法一:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_dialog, null);
Dialog dialog = new Dialog(getActivity(), 0);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(true);
//Do something
// 设置宽度为屏宽、位置靠近屏幕底部
Window window = dialog.getWindow();
//设置了窗口的背景色为透明,这一步是必须的
// <color name="transparent">#50000000</color>
window.setBackgroundDrawableResource(R.color.transparent);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
//设置窗口的宽度为 MATCH_PARENT,效果是和屏幕宽度一样大
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
return dialog;
}

法二:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE, 0);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setCanceledOnTouchOutside(true);
View rootView = inflater.inflate(R.layout.fragment_dialog, container, false);
//Do something
// 设置宽度为屏宽、靠近屏幕底部。
final Window window = getDialog().getWindow();
//这步是必须的
window.setBackgroundDrawableResource(R.color.transparent);
//必要,设置 padding,这一步也是必须的,内容不能填充全部宽度和高度
window.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
return rootView;
}

3.5 应用场景的区别是什么

文章一开始简单总结了法一 和法二的应用场景,这里说明下:

  • 法一:为简单的替代 Dialog 提供了非常方便的创建方式,但是在使用了多线程(例如网络请求)的情况下,不能正确的获取当前 Fragment 的状态,会产生空指针异常
  • 法二:则没有如上空指针的问题,而且,其创建方式默认使用了自定义 View,更便于应对复杂 UI 的场景

3.6 如何与 Activity 进行交互?

使用回调的方式

a.在 DialogFragment 中:

public interface OnDialogListener {
void onDialogClick(String person);
} private OnDialogListener mlistener; public void setOnDialogListener(OnDialogListener dialogListener){
this.mlistener = dialogListener;
}

DialogFragment 的点击事件中:

public OnDialogListener mlistener;
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv1:
mlistener.onDialogClick("1");
dismiss();
break;
case R.id.tv2:
mlistener.onDialogClick("2");
dismiss();
break;
case R.id.tv3:
mlistener.onDialogClick("3");
dismiss();
break;
case R.id.tv4:
mlistener.onDialogClick("4");
dismiss();
break;
}
}

b.在 Activity

dialogFragment.setOnDialogListener(new PersonDialogFragment.OnDialogListener() {
@Override
public void onDialogClick(String person) {
ToastUtil.showToast(person);
}
});

3.7 如何结合动画使用

a.设置从下到上弹出的动画

private void slideToUp(View view) {
Animation slide = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0);
slide.setDuration(400);
slide.setFillEnabled(true);
slide.setFillAfter(true);
view.startAnimation(slide);
}

b.设置从上到下弹出的动画

private boolean isAnimation = false;//用来判断是否多次点击。防止多次执行

public void slideToDown(View view) {
Animation slide = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 1.0f);
slide.setDuration(400);
slide.setFillEnabled(true);
slide.setFillAfter(true);
view.startAnimation(slide);
slide.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
} @Override
public void onAnimationEnd(Animation animation) {
//用来判断是否多次点击。防止多次执行
isAnimation = false;
//弹框消失
IOSDialogFragment.this.dismiss();
} @Override
public void onAnimationRepeat(Animation animation) {
}
});
}

c.封装从上到下弹出的动画

加上判断是否多次点击。防止多次执行

private void dialogFinish() {
if (isAnimation) {
return;
}
isAnimation = true;
slideToDown(rootView);
}

3.8 如何在 Activity 弹出 DialogFragment ?

mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
IOSDialogFragment fragment = new IOSDialogFragment();
//第二个参数是 tag
fragment.show(getSupportFragmentManager(), "android");
}
});

3.9 如何点击空白处时关闭的时候,还能使用动画?

直接对 DecorView 设置 onTouchListener

window.getDecorView().setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//弹框消失的动画执行相关代码
....
.... }
return true;
}
});

四、结语

终于看完了鸭!累死鸭了!如果还有什么不是很清楚的话,可以看下笔者写的示例 Demo


如果文章对您有一点帮助的话,希望您能点一下赞,您的点赞,是我前进的动力

本文参考链接:

本文使用 mdnice 排版

手把手带你玩转 DialogFragment的更多相关文章

  1. Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战

    转: Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战 Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一 ...

  2. Android 手把手带你玩转自己定义相机

    本文已授权微信公众号<鸿洋>原创首发,转载请务必注明出处. 概述 相机差点儿是每一个APP都要用到的功能,万一老板让你定制相机方不方?反正我是有点方. 关于相机的两天奋斗总结免费送给你. ...

  3. 手把手教你玩转 CSS3 3D 技术

    css3的3d起步 要玩转css3的3d,就必须了解几个词汇,便是透视(perspective).旋转(rotate)和移动(translate).透视即是以现实的视角来看屏幕上的2D事物,从而展现3 ...

  4. 手把手教你玩转CSS3 3D技术

    手把手教你玩转 CSS3 3D 技术   要玩转css3的3d,就必须了解几个词汇,便是透视(perspective).旋转(rotate)和移动(translate).透视即是以现实的视角来看屏幕上 ...

  5. 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三

       手把手叫你玩转网络编程系列之三    完毕port(Completion Port)具体解释                                                    ...

  6. wing带你玩转自定义view系列(1) 仿360内存清理效果

    本篇是接自 手把手带你做自定义view系列 宗旨都是一样,带大家一起来研究自定义view的实现,与其不同的是本系列省去了简单的坐标之类的讲解,重点在实现思路,用简洁明了的文章,来与大家一同一步步学习. ...

  7. [.Net] 手把手带你将自己打造的类库丢到 NuGet 上

    手把手带你将自己打造的类库丢到 NuGet 上 序 我们习惯了对项目右键点击“引用”,选择“管理NuGet 程序包”来下载第三方的类库,可曾想过有一天将自己的打造的类库放到 NuGet 上,让第三者下 ...

  8. 带你玩转Visual Studio

    带你玩转Visual Studio 带你新建一个工程 工程目录下各文件的含义 解决方案与工程 在这之前先了解一个概念:解决方案与工程. 解决方案(Solution):一个大型项目的整体的工作环境: 工 ...

  9. 来吧!带你玩转 Excel VBA

    来吧!带你玩转 Excel VBA 从错失良机到艰辛的DOS征程,从坎坷购机自学路到转机起程,从爱好到事业,他从一个完全不懂电脑的人到VBA高级应用者,一切全是自学…… 我是罗刚君,来自四川的一个小县 ...

随机推荐

  1. Eureka心跳健康检查机制和Spring boot admin 节点状态一直为DOWN的排查(忽略某一个节点的健康检查)

    https://www.jdon.com/springcloud/eureka-health-monitoring.html 运行阶段执行健康检查的目的是为了从Eureka服务器注册表中识别并删除不可 ...

  2. 慕课网--java权限管理系统

    http://coding.imooc.com/class/evaluation/149.html

  3. 手把手教你使用Python抓取QQ音乐数据(第二弹)

    [一.项目目标] 通过Python爬取QQ音乐数据(一)我们实现了获取 QQ 音乐指定歌手单曲排行指定页数的歌曲的歌名.专辑名.播放链接. 此次我们在之前的基础上获取QQ音乐指定歌曲的歌词及前15个精 ...

  4. express高效入门教程(5)

    5.ejs模版 5.1.什么是模版引擎? 为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. 在后端开发中,处理数据的代码和展示 ...

  5. js语法基础入门(7)

    7.数组 7.1.什么是数组以及相关概念? 什么是数组?是一组数据有序排列的集合.将一组数据按一定顺序组织为一个组合,并对这个组合命名,这样便构成了数组. 什么是数组元素?组成数组的每一个数据称为数组 ...

  6. Shader专题:卡通着色(一)控制颜色的艺术

    什么是 Shader? 关于什么是 Shader ,各种百科各种教程都有说过,但是今天我们就从一个另一个角度去试着理解什么是 Shader? 我们先看下 Shade 的英文意思,如下: v.给...遮 ...

  7. 基于小程序请求接口 wx.request 封装的类 axios 请求

    基于小程序请求接口 wx.request 封装的类 axios 请求 Introduction wx.request 的配置.axios 的调用方式 源码戳我 feature 支持 wx.reques ...

  8. 洛谷 P1215 【[USACO1.4]母亲的牛奶 Mother's Milk】

    这道题\(DFS\)就好了,六种情况,\(ab,ac,ba,bc,ca,cb\),我们直接枚举就可.什么?这样不会结束?用一个\(vis\)数组判断走过没有就可以了.最后排序输出即可. \(code: ...

  9. windows快速安装redis

    下载地址:https://github.com/microsoftarchive/redis/releases 下载解压,命令行:redis-server.exe redis.windows.conf

  10. NIVIDIA Tegra K1 QWT安装使用问题和解决办法

    在Linux系统下,Tegra K1(ARM体系),只有QtCreator的环境下,去安装Qwt6.1.0: 下载: 系统安装好之后,直接联网在系统自带的软件安装程序中搜索Qt,安装Qt5.2.1,之 ...