欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发之DialogFragment用法实例总结

程序员文章站 2022-06-19 19:09:10
本文实例讲述了android开发之dialogfragment用法。分享给大家供大家参考,具体如下: 背景 android 官方推荐使用 dialogfragment...

本文实例讲述了android开发之dialogfragment用法。分享给大家供大家参考,具体如下:

背景

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

而创建 dialogfragment 有两种方式:

1. 覆写其 oncreatedialog 方法 — ①
2. 覆写其 oncreateview 方法 — ②

虽然这两种方式都能实现相同的效果,但是它们各有自己适合的应用场景:

1. 方法 ①,一般用于创建替代传统的 dialog 对话框的场景,ui 简单,功能单一。
2. 方法 ②,一般用于创建复杂内容弹窗或全屏展示效果的场景,ui 复杂,功能复杂,一般有网络请求等异步操作。

应用

基本用法

对于方法 ①,创建一个 dialog 并返回它即可:

@override
public dialog oncreatedialog(bundle savedinstancestate) {
 //为了样式统一和兼容性,可以使用 v7 包下的 alertdialog.builder
 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();
}

当然,你也可以使用自定义 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;
}

对于方法 ②,和普通的 fragment 用法基本一致:

@override
public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) {
 view rootview = inflater.inflate(r.layout.fragment_dialog, container, false);
 // do someting
 return rootview;
}
/**
 * 设置主题需要在 oncreate() 方法中调用 setstyle() 方法
 */
@override
public void oncreate(@nullable bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setstyle(dialogfragment.style_no_title, r.style.customdialog);
}

处理屏幕翻转

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

无标题栏/全屏

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

无标题栏

对于方法 ① :

@override
public dialog oncreatedialog(bundle savedinstancestate) {
 layoutinflater inflater = getactivity().getlayoutinflater();
 view view = inflater.inflate(r.layout.fragment_dialog, null);
 dialog dialog = new dialog(getactivity(), r.style.customdialog);
  // 关闭标题栏,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() 的第一个参数有四个可选值:
 * style_normal|style_no_title|style_no_frame|style_no_input
 * 其中 style_no_title 和 style_no_frame 可以关闭标题栏
 * 每一个参数的详细用途可以直接看 android 源码的说明
 */
 setstyle(dialogfragment.style_no_title, r.style.customdialog);
}

实现全屏(宽/高度全屏)

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

方法 ① :

@override
public dialog oncreatedialog(bundle savedinstancestate) {
 layoutinflater inflater = getactivity().getlayoutinflater();
 view view = inflater.inflate(r.layout.fragment_dialog, null);
 dialog dialog = new dialog(getactivity(), r.style.customdialog);
 dialog.requestwindowfeature(window.feature_no_title);
 dialog.setcontentview(view);
 dialog.setcanceledontouchoutside(true);
 //do something
  // 设置宽度为屏宽、位置靠近屏幕底部
 window window = dialog.getwindow();
 window.setbackgrounddrawableresource(r.color.transparent);
 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 dialog;
}

代码 12 行设置了窗口的背景色为透明,这一步是必须的;

代码 15 行设置窗口的宽度为 match_parent,效果是和屏幕宽度一样大,同样你也可以设置高度的值。设置宽度和高度除了 match_parentwrap_content ,也可以直接设置成具体的数值。

方法 ②:

@override
public void oncreate(@nullable bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setstyle(dialogfragment.style_no_title, r.style.customdialog);
}
@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);
    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;
}

代码 14 行设置了窗口的背景色为透明,这一步是必须的;

代码 15 行设置了窗口的 pading 值全部为0,这一步也是必须的,内容不能填充全部宽度和高度。

其他的和 ① 中的类似。

应用场景区别

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

1. 从基本的用法中可以看到方法 ① 为简单的替代 dialog 提供了非常方便的创建方式,比方法 ② 有优势
2. 方法 ① 在使用了多线程(例如网络请求)的情况下,不能正确的获取当前 fragment 的状态,会产生空指针异常。方法 ② 则没有此问题,而且,其创建方式默认使用了自定义 view,更便于应对复杂 ui 的场景。

这里举例说明:方法 ① 和方法 ② 的//do something 代码处,我们进行一些异步操作:

textview title = rootview.findviewbyid(r.id.dialoag_tv);
title.settext("value a");
new sometask().execute(url);
private class sometask extends asynctask<string, void, boolean> {
    @override
    protected boolean doinbackground(string... params) {
      // 一些网络请求
      // 成功时 return true;
      // 异常时 return false;
    }
    @override
    protected void onpostexecute(boolean aboolean) {
      super.onpostexecute(aboolean);
      // if (!isvisible()) return;
      if (aboolean) {
        title.settext("value b");
      }
    }
}

如果在网络请求未结束或者刚结束时关闭了当前 dialogfragment ,代码 19 行就会报空指针异常了,代码 17 的作用就是判断 dialogfragment 当前的状态是否为可用态,但是 isvisible() 以及 ishide() 对于方法 ① 无法正确返回其状态,方法 ② 则正常。方法 ① 和方法 ② 创建 dialogfragment 的一些状态并不是完全一致。

ps:你也可以使用静态 handler 结合弱引用等来处理异步操作,那样对 dialogfragment 状态的获取就不重要了。

总结

以上是个人在实际开发过程中的一点总结和看法,希望你能抱着存疑的态度进行尝试,如果有新的观点或者文章中有不正确的地方,欢迎和我联系。

更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android调试技巧与常见问题解决方法汇总》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。