DialogFragment运行原理及使用方法详解

思维导图

一、为什么要学习 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

https://github.com/LoveLifeEveryday/TestDialogFragment

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android开发之基于DialogFragment创建对话框的方法示例

    本文实例讲述了Android基于DialogFragment创建对话框的方法.分享给大家供大家参考,具体如下: /** * 使用DialogFragment创建对话框 * @description: * @author ldm * @date 2016-5-12 下午2:00:01 */ public class FragmentAlertDialog extends Activity { private Button button; @Override protected void onCre

  • 解决Android中自定义DialogFragment解决宽度和高度问题

    关于详解Android应用中DialogFragment的基本用法,大家可以参考下. 1. 概述 DialogFragment在android 3.0时被引入.是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框.典型的用于:展示警告框,输入框,确认框等等. 在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog.注:官方不推荐直接使用Dialog创建对话框. 2. 好处与用法 使用DialogFragment来管理对话

  • Android开发之DialogFragment用法实例总结

    本文实例讲述了Android开发之DialogFragment用法.分享给大家供大家参考,具体如下: 背景 Android 官方推荐使用 DialogFragment 来代替 Dialog ,可以让它具有更高的可复用性(降低耦合)和更好的便利性(很好的处理屏幕翻转的情况). 而创建 DialogFragment 有两种方式: 1. 覆写其 onCreateDialog 方法 - ① 2. 覆写其 onCreateView 方法 - ② 虽然这两种方式都能实现相同的效果,但是它们各有自己适合的应用

  • 详解Android应用中DialogFragment的基本用法

    DialogFragment的基本用法 1. 创建DialogFragment public class DialogA extends DialogFragment implements DialogInterface.OnClickListener { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder

  • Android中使用DialogFragment编写对话框的实例教程

    Android提供alert.prompt.pick-list,单选.多选,progress.time-picker和date-picker对话框,并提供自定义的dialog.在Android 3.0后,dialog基于fragment,并对之前版本提供兼容支持库,也就是说对于开发者而言,dialog是基于DialogFragment的,但此时需要在应用中加入相关的兼容库. 和Windows或者网页JS的Dialog不同,Android的dialog是异步的,而不是同步的.对于同步的dialog

  • Android 之BottomsheetDialogFragment仿抖音评论底部弹出对话框效果(实例代码)

    实现的效果图: 自定义Fragment继承BottomSheetDialogFragment 重写它的三个方法: onCreateDialog() onCreateView() onStart() 他们的执行顺序是从上到下 import android.app.Dialog; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable;

  • Android中DialogFragment自定义背景与宽高的方法

    介绍 DialogFragment在android 3.0时被引入.是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框.典型的用于:展示警告框,输入框,确认框等等. 在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog.注:官方不推荐直接使用Dialog创建对话框. 本文主要给大家介绍了关于Android中DialogFragment自定义背景与宽高的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的

  • DialogFragment运行原理及使用方法详解

    思维导图 一.为什么要学习 DialogFragment 你还在用 Dialog 吗?你还在经常烦恼于屏幕翻转的时候,Dialog 的各种奇葩情况吗?你想降低耦合吗?如果你有其中的一个烦恼,那么恭喜你,遇见了 DialogFragment ,他恰巧就解决了上面所说的问题,如果感兴趣的话,随笔者来看下吧! 二.背景 Android 官方推荐使用 DialogFragment 来代替 Dialog ,可以让它具有更高的可复用性(降低耦合)和更好的便利性(很好的处理屏幕翻转的情况).而创建 Dialo

  • ThreadPoolExecutor线程池原理及其execute方法(详解)

    jdk1.7.0_79 对于线程池大部分人可能会用,也知道为什么用.无非就是任务需要异步执行,再者就是线程需要统一管理起来.对于从线程池中获取线程,大部分人可能只知道,我现在需要一个线程来执行一个任务,那我就把任务丢到线程池里,线程池里有空闲的线程就执行,没有空闲的线程就等待.实际上对于线程池的执行原理远远不止这么简单. 在Java并发包中提供了线程池类--ThreadPoolExecutor,实际上更多的我们可能用到的是Executors工厂类为我们提供的线程池:newFixedThreadP

  • Python堆排序原理与实现方法详解

    本文实例讲述了Python堆排序原理与实现方法.分享给大家供大家参考,具体如下: 在这里要事先说明一下我也是新手,很多东西我了解不是很深入,写算法完全是锻炼自己逻辑能力同时顺带帮助读研的朋友么解决一些实际问题.所以很多时候考虑的东西不是很全面能请各位看到博文的大牛们指正.对于排序算法说实在的我觉得已经写烂了,但是为什么还是要过一遍呢?还是为了能够打牢基础.说一下自己的看法,对于已经的玩烂的算法因该怎么学.首先最重要的还是了解算法的基本模型和算法思想,我觉得这是非常重要的.其次的话首先先尝试自己实

  • JSONP跨域原理以及实现方法详解

    目录 前言 一.同源策略和跨域 1.1 同源策略 1.1.1 什么是同源 1.1.2 什么是同源策略 1.2 跨域 1.2.1 什么是跨域 1.2.2 浏览器对跨域请求的拦截 1.2.3 如何实现跨域数据请求 二.JSONP 概述 2.1 JSONP原理 2.2 优点 2.3 缺点 三.JSONP 应用流程 四.JSONP 实现 3.1 简单的实例: 3.2 可靠的 JSONP 实例: 五.JSONP安全性问题 5.1 CSRF攻击 5.2 XSS漏洞 5.3 服务器被黑,返回一串恶意执行的代码

  • PHP接口继承及接口多继承原理与实现方法详解

    本文实例讲述了PHP接口继承及接口多继承原理与实现方法.分享给大家供大家参考,具体如下: 在PHP的接口中,接口可以继承接口.虽然PHP类只能继承一个父类(单继承),但是接口和类不同,接口可以实现多继承,可以继承一个或者多个接口.当然接口的继承也是使用extends关键字,要多个继承的话只要用逗号把继承的接口隔开即可. 需要注意的是当你接口继承其它接口时候,直接继承父接口的静态常量属性和抽象方法,所以类实现接口时必须实现所有相关的抽象方法. 现在你对PHP接口的继承有所了解了吧,下面的例子可供参

  • php脚本守护进程原理与实现方法详解

    本文实例讲述了php脚本守护进程原理与实现方法.分享给大家供大家参考,具体如下: 思路: 1. while 循环,若当前没有数据要操作可以休眠: 2. crontab 脚本每隔固定时间段执行该脚本,执行时先检测是否已在执行,若无 执行,有则 跳过. 3. nohup  后台执行 4. flock -xn  加锁 实例: 要执行代码:index.php <?php set_time_limit(0); //死循环 while(1) { $message = '1111111' . "\n&q

  • Java笛卡尔积算法原理与实现方法详解

    本文实例讲述了Java笛卡尔积算法原理与实现方法.分享给大家供大家参考,具体如下: 笛卡尔积算法的Java实现: (1)循环内,每次只有一列向下移一个单元格,就是CounterIndex指向的那列. (2)如果该列到尾部了,则这列index重置为0,而CounterIndex则指向前一列,相当于进位,把前列的index加一. (3)最后,由生成的行数来控制退出循环. public class Test { private static String[] aa = { "aa1", &q

  • JavaScript动态检测密码强度原理及实现方法详解

    本文实例讲述了JavaScript动态检测密码强度原理及实现方法.分享给大家供大家参考,具体如下: 在注册账户,设置密码时,会出现密码强度动态检测,网上看了一些帖子,大多只写了具体的实现过程,而没有对原理的分析过程.下面着重讲一下其原理. 原理分析 通常实现密码强度动态判断有两种方案实现: 正则.但其效率低一点,难度也大一些. 字符串,函数和运算符. 这里用第二种方案,但是如何判断一个密码串是强还是弱呢? 一般我们的密码会设置为数字.字母(大小写).特殊符号三类. 强:密码串包含其中三种或以上

  • PHP高级编程之消息队列原理与实现方法详解

    本文实例讲述了PHP高级编程之消息队列原理与实现方法.分享给大家供大家参考,具体如下: 1. 什么是消息队列 消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式 2. 为什么使用消息队列 消息队列技术是分布式应用间交换信息的一种技术.消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读出.通过消息队列,应用程序可独立地执行,它们不需要知道彼此的位置.或在继续执行前不需要等待接收程序接收此消息. 3. 什么场合使用消息队列 你首先需要弄清楚,消息

  • Python通过TensorFLow进行线性模型训练原理与实现方法详解

    本文实例讲述了Python通过TensorFLow进行线性模型训练原理与实现方法.分享给大家供大家参考,具体如下: 1.相关概念 例如要从一个线性分布的途中抽象出其y=kx+b的分布规律 特征是输入变量,即简单线性回归中的 x 变量.简单的机器学习项目可能会使用单个特征,而比较复杂的机器学习项目可能会使用数百万个特征. 标签是我们要预测的事物,即简单线性回归中的 y 变量. 样本是指具体的数据实例.有标签样本是指具有{特征,标签}的数据,用于训练模型,总结规律.无标签样本只具有特征的数据x,通过

随机推荐