Android进阶之路 - DialogFragment有没有了解的必要?

几个月前写到了弹框业务,以前经常用Dialog、ButtomDialog 、popupWindow 组件,为了契合项目结构参考了原有的 DialogFragment 组件,特此予以记录

我一般在项目中写弹框组件的话,主要用到 alertDialogpopupWindow 组件,关于 DialogFragment 组件将在该篇简单学一下

弹框

  • Dialog 基础入门 - 普通对话框、水平进度条对话框、普通列表对话框、单选对话框、复选对话框
  • ButtomDialog 使用方式(早期所写,回头看来当时词不达意,本质还是用了alertDialog ,参考意义不大)
  • popupWindow 使用方式 - 个人认为可以和Dialog一较高下,项目中使用相对频繁,定制化也高
  • 用Kotlin写个能让我进步的Dialog - 近几年因为Kotlin盛行,写了一个项目中的应用场景

Tip:嗯… 可以了解,但是如果你已经掌握了其他弹框技术,在无特定需求下可以先不学,毕竟这么多年下来这款组件的普及率、使用率好像并不太高,而我也在逐渐替换掉项目中 DialogFragment 的使用场景…

六月梅雨季

    • 基础了解
    • 函数分析
    • 实战检验

基础了解

起初其实我不太理解为何要用DialogFragment?它相比常用弹框组件的优势在哪里?

通过DialogFragment源码可以确定其继承自Fragment故拥有其特性,同时实现了Dialog接口监听弹框的一个取消状态、关闭状态

在这里插入图片描述

查看内部方法并不多,除了 Dilaog 的一些show、dismiss方法外,我觉得最能引起能注意的应该就是生命周期的特性了,所以这应该算是这款组件的一个优势,可以动态监听与Activity的绑定状态,以及自身的一个生命周期状态

在这里插入图片描述

单从以上源码来看,目前为止至少具备一些基础优势

  • 生命周期清晰,扩展了适用场景
  • 支持弹框布局自定义化
  • 支持Dialog相关设置
  • 与Activity生命周期绑定,会随着Activity消失而消失(未复测)

函数分析

当我们创建 DialogFragment 时,因未声明抽象方法,所以我们根据需求,可自行选择重写几个关键方法,如

  • onCreate:生命周期第一步,一般根据业务可获取创建DialogFragment时的入参,用于当前组件显示等
  • onCreateView: 用于设置弹框布局、事件处理
  • onCreateDialog:可在此处调用其Dialog特性
  • onResume:弹窗展示,可在此处获取当前显示的Dialog,便于设置一些特定属性,常用于设置组件展示范围、形式
  • onDismiss: 监听弹窗消失,根据业务需求自行加入逻辑
  • onActivityCreated:便于监听Activity的状态,支持Activity关联创建后,及时展示DialogFragment(方法已过时,未用过)

onCreate

    @Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle bundle = getArguments();//获取外部传入的数据String ourContent = bundle.getString("keyContent");}

onCreateView

绑定弹框要显示的布局,同时可以设置一些组件显示、事件等

    @Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.our_layout, container, false);TextView tvContent = rootView.findViewById(R.id.tv_content);TextView tvClose = rootView.findViewById(R.id.tv_close);tvClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dismissAllowingStateLoss();}});tvContent.setOnClickListener(ourClick);return rootView;}

有的人蛮喜欢抽方法,其实本质相同,这里就是将点击事件抽到了外部(建议初方法内部复杂、繁琐、调用频繁外,并不推荐抽方法)

    View.OnClickListener ourClick = new View.OnClickListener() {@Overridepublic void onClick(View v) {dismissAllowingStateLoss();}};

onCreateDialog

关于Dialog属性设置,可以在此处进行设置,例如触摸、点击视图以外区域不会关闭弹框等

    @NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Dialog dialog = super.onCreateDialog(savedInstanceState);// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);dialog.setCanceledOnTouchOutside(false);return dialog;}

onResume

显示时设置弹框大小、位置、背景等

    @Overridepublic void onResume() {super.onResume();Dialog dialog = getDialog();if (dialog != null && dialog.getWindow() != null) {dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;layoutParams.gravity = Gravity.CENTER;dialog.getWindow().setAttributes(layoutParams);}}

onDismiss

通常为了灵活性,我们大多会监听弹框消失做一些逻辑处理,不过也不排除一些固有行为直接在组件内部实现

    @Overridepublic void onDismiss(DialogInterface dialog) {super.onDismiss(dialog);
// 可自行做一些数据记录之类的  SPUtils.AppSP().put("key", "value");}

关于 DialogFragment 常用函数,我们已经都说完了,那么简单说一下它的调用方式,通常我们主要有俩种常见方式

  • 创建 DialogFragment 实例后,调用类似show()函数显示弹框

在这里插入图片描述

  • DialogFragment 内部提供静态方法

有的说遇到了 Fragment already added(重复添加) 的问题,可以参考下方DialogFragment 内部提供的静态方法

  /*** 静态方法,支持便捷调用,同时传入所需参数*/public static OurFirstDialogFragment display(final FragmentManager fragmentManager, String contentUrl) {OurFirstDialogFragment fragment = (OurFirstDialogFragment) fragmentManager.findFragmentByTag(OurFirstDialogFragment.class.getCanonicalName());if (fragment == null) {fragment = new OurFirstDialogFragment();Bundle bundle = new Bundle();bundle.putString(KEY_CONTENT, contentUrl);fragment.setArguments(bundle);}if (!fragment.isAdded()) {fragment.show(fragmentManager, OurFirstDialogFragment.class.getCanonicalName());}return fragment;}

关于 DialogFragment 显示,通常有showshowNow函数,主要区别于此

  • show显示稍慢于showNow,这导致调用show了后,立刻修改dialog中的view(例如textView修改字符内容)会崩溃,而showNow不会(showNow容错率更高
  • 待检验:(废弃)展示弹窗后fragment对象会添加到activity,showNow会在弹窗dismiss消失后移除fragment,show不会移除
    (以前同一个对象非连续地调用两次show会崩溃,现在不会了,可能是google更新了,使show也在弹窗消失后移除了)
  • 待检验:不可连续地调用show或者showNow;这个“连续”是指在弹窗还没有消失的时候再次调用,原因在上方说了,展示弹窗后fragment对象会添加到activity,而同一个fragment只能添加一次,所以连续调用可能会崩溃

实战检验

调用方式

涉及到了Fragment,所以一般会用到fragmentManager ,在Activity、Fragment都有现成API

 //当前我用的是静态函数,可以直接通过类型+函数调用//关于调用函数,如果为了兼容多场景,可以重载其静态方法OurFirstDialogFragment .display(fragmentManager) //不传值OurFirstDialogFragment .display(fragmentManager,"数据") //传值//通过创建实例的方式,显示弹框,因项目未采用此方式,仅做示例var ourFirstDialogFragment = OurFirstDialogFragment()fragmentManager?.let { ourFirstDialogFragment.show(it, "tag一般独一无二,防止重复") }

OurFirstDialogFragment(自定义DialogFragment )

package xx;import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;public class OurFirstDialogFragment extends DialogFragment {public static final String KEY_CONTENT = "KEY_CONTENT";private String ourContent;private TextView tvContent, tvClose;/*** 静态方法,支持便捷调用,同时传入所需参数*/public static OurFirstDialogFragment display(final FragmentManager fragmentManager, String content) {OurFirstDialogFragment fragment = (OurFirstDialogFragment) fragmentManager.findFragmentByTag(OurFirstDialogFragment.class.getCanonicalName());if (fragment == null) {fragment = new OurFirstDialogFragment();Bundle bundle = new Bundle();bundle.putString(KEY_CONTENT, content);fragment.setArguments(bundle);}if (!fragment.isAdded()) {fragment.show(fragmentManager, OurFirstDialogFragment.class.getCanonicalName());}return fragment;}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);Bundle bundle = getArguments();//获取外部传入的数据ourContent = bundle.getString(KEY_CONTENT);}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.our_layout, container, false);tvContent = rootView.findViewById(R.id.tv_content);tvClose = rootView.findViewById(R.id.tv_close);tvClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {dismissAllowingStateLoss();}});tvContent.setOnClickListener(ourClick);return rootView;}View.OnClickListener ourClick = new View.OnClickListener() {@Overridepublic void onClick(View v) {dismissAllowingStateLoss();}};@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {Dialog dialog = super.onCreateDialog(savedInstanceState);// dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);dialog.setCanceledOnTouchOutside(false);return dialog;}@Overridepublic void onResume() {super.onResume();Dialog dialog = getDialog();if (dialog != null && dialog.getWindow() != null) {dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;layoutParams.gravity = Gravity.CENTER;dialog.getWindow().setAttributes(layoutParams);}}@Overridepublic void onDismiss(DialogInterface dialog) {super.onDismiss(dialog);//SPUtils.AppSP().put("key", "value");}}

嗯,当你看到这儿的话,不知道你是否遇到了下面这个问题,当我们在Dialog内部操作时,我们希望外部可以实时监听,这时候就用到了接口回调

    public interface DialogCallback {void onButtonClicked(String buttonText);}private DialogCallback callback;public static OurFirstDialogFragment display(final FragmentManager fragmentManager, String content) {OurFirstDialogFragment fragment = (OurFirstDialogFragment) fragmentManager.findFragmentByTag(OurFirstDialogFragment.class.getCanonicalName());if (fragment == null) {fragment = new OurFirstDialogFragment();Bundle bundle = new Bundle();bundle.putString(KEY_CONTENT, content);fragment.setArguments(bundle);}//在静态方法中绑定监听回调,如果你采用的是实例调用,需要重写构造参数,然后在绑定监听回调fragment.callback = callback;if (!fragment.isAdded()) {fragment.show(fragmentManager, OurFirstDialogFragment.class.getCanonicalName());}return fragment;}tvView.setOnClickListener(v -> {dismissAllowingStateLoss();callback.onButtonClicked("动态回传要监听的内容即可");});

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

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

相关文章

用GPT-4纠错GPT-4 OpenAI推出CriticGPT模型

根据OpenAI周四(6月27日)发布的新闻稿,该公司新推出了一个基于GPT-4的模型——CriticGPT,用于捕获ChatGPT代码输出中的错误。CriticGPT的作用相当于让人们用GPT-4来查找GPT-4的错误。该模型可以对ChatGPT响应结果做出批评评论&…

有没有能用蓝牙的游泳耳机,性能超凡的4大游泳耳机力荐

在现代科技的推动下,越来越多具备蓝牙功能的游泳耳机正在改变游泳爱好者的体验方式。这些创新产品不仅在防水性能上有了显著提升,还能让您在水中享受到高质量的音乐。然而,选择一款优秀的蓝牙游泳耳机并不简单,需要考虑到防水等级…

【秋招突围】2024届秋招笔试-科大笔试题-01-三语言题解(Java/Cpp/Python)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系计划跟新各公司春秋招的笔试题 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 文章目录 &#x1f4d6…

基于SSM的大学生家教管理系统【附源码+LW】

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本大学生家教平台就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&a…

c语言--指针

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理c语言中指针的相关知识点。 指针概念 指针存储的就是数据的地址。 直观理解: 李华家是北洋路130号1单元101 用变量处理数据: 我们去李华家拿数据。 用指针处理数据: 我们去北洋路130号1单元101拿数据…

Paragon NTFS与Tuxera NTFS有何区别 Mac NTFS 磁盘读写工具选哪个好

macOS系统虽然以稳定、安全系数高等优点著称,但因其封闭性,不能对NTFS格式磁盘写入数据常被人们诟病。优质的解决方案是使用磁盘管理软件Paragon NTFS for Mac(点击获取激活码)和Tuxera NTFS(点击获取激活码&#xff0…

2024年科技型中小企业申报指南

01 什么是科技型中小企业 科技型中小企业是指依托一定数量的科技人员从事科学技术研究开发活动,取得自主知识产权并将其转化为高新技术产品或服务,从而实现可持续发展的中小企。 02 申请“科技型中小企业”的好处 一、政策扶持与优惠 1.税收减免&…

Vue2组件传值(通信)的方式

1.父传后代 ( 后代拿到了父的数据 ) 1. 父组件引入子组件&#xff0c;绑定数据 <List :str1‘str1’></List> 子组件通过props来接收props:{str1:{type:String,default:}}***这种方式父传子很方便&#xff0c;但是父传给孙子辈分的组件就很麻烦&#xff08;父》子…

《GPT模型揭秘:数据驱动AI的核心概念与GPT系列对比分析》

DS&#xff1a;《What Are the Data-Centric AI Concepts behind GPT Models?通过三个数据为中心的人工智能目标(训练数据开发、推理数据开发和数据维护)揭示GPT模型背后的数据为中心的人工智能概念》解读—GPT-1/GPT-2/GPT-3系列对比(语料大小参数量解码层数上下文长度隐藏层…

技术学习的奥秘与乐趣

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 在当今快速发展的科技时代&#xff0c;学习技术已经成为了许多人追求的重要目标之一。无论是为了个人发展&#…

并发编程基础概念

相关概念 并行 并行是指同一个时刻&#xff0c;多个任务同时进行。只有在多核CPU下才会发生。 并发 并发是指单个CPU在不同任务之间来换切换工作&#xff0c;但是同一时刻只有一个任务在工作。由于CPU的切换速度很快&#xff0c;给人的感受是多个任务在一起运行。 串行 串行…

Ansys Zemax|在设计抬头显示器(HUD)时需要使用哪些工具?

附件下载 联系工作人员获取附件 汽车抬头显示器或汽车平视显示器&#xff0c;也被称为HUD&#xff0c;是在汽车中显示数据的透明显示器&#xff0c;不需要用户低头就能看到他们需要的重要资讯。这个名字的由来是由于该技术能够让飞行员在头部“向上”并向前看的情况下查看信息…

RocketMQ快速入门:linux安装rocketmq并配置开机自启(十一)

目录 0. 引言1. 下载安装包1.1 高版本直接下载安装包1.2 下载源码包进行编译 2. namesrv和broker安装2.1 安装2.2 放开服务器端口2.3 测试 3. 配置开机自启3.1 配置namesrv开机自启3.2 配置broker开机自启 0. 引言 之前我们针对本机电脑安装rocketmq进行了讲解&#xff0c;同时…

Java--回顾方法的定义

1.修饰符 public 公共的 修饰String类型 2.返回类型 返回的值得类型 返回值为String&#xff08;字符串&#xff09;类型 3.break continue return的区别 break&#xff0c;结束整个循环 continue&#xff0c;结束本次循环 return&#xff0c;结束整…

远程过程调用RPC实现原理

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

运算放大器输出相位反转和输入过压保护

运算放大器输出电压相位反转 本教程讨论两个与运算放大器相关的话题&#xff1a;输出相位反转和输入过压保护。 超过输入共模电压(CM)范围时&#xff0c;某些运算放大器会发生输出电压相位反转问题。其原因通常是运算放大器的一个内部级不再具有足够的偏置电压而关闭&#xff…

昇思25天学习打卡营第4天|常见的数据变换 Transforms类型

导入数据集相关库和模块 首先导入了一些必要的库和模块&#xff0c;包括 numpy&#xff08;np 是其常用的别名&#xff09;、PIL 库中的 Image 模块&#xff0c;以及自定义的 download 模块&#xff0c;还有 mindspore.dataset 中的 transforms、vision、text 模块。然后使用 m…

数字信号处理实验三(IIR数字滤波器设计)

IIR数字滤波器设计&#xff08;2学时&#xff09; 要求&#xff1a; 产生一复合信号序列&#xff0c;该序列包含幅度相同的28Hz、50Hz、100Hz、150Hz的单音&#xff08;单频&#xff09;信号&#xff1b;其中&#xff0c;50Hz及其谐波为工频干扰&#xff08;注&#xff1a;采样…

2024年6月27日,欧盟REACH法规新增第31批1项SVHC高关注物质

ECHA公布第31批1项SVHC&#xff0c;物质已增至241项 2024年6月27日&#xff0c;ECHA公布第31批1项SVHC&#xff0c;总数达241项。新增物质未包括磷酸三苯酯&#xff0c;仍在评议中。REACH法规要求SVHC含量超0.1%需告知下游&#xff0c;出口超1吨须通报ECHA。SCIP通报要求SVHC含…

MySQL84 -- ERROR 1524 (HY000): Plugin ‘msql_native_password‘ is not loaded.

【问题描述】 MySQL 8.4版本&#xff0c;配置用户使用mysql_native_password认证插件验证用户身份&#xff0c;报错&#xff1a; 【解决方法】&#xff08;Windows, MySQL 8.4) 1、修改MySQL配置文件my.ini&#xff0c;在[mysqld]段添加mysql_native_passwordON。 2、管理员…