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

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

onCreateView

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

    @Nullable
    @Override
    public 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() {
            @Override
            public void onClick(View v) {
                dismissAllowingStateLoss();
            }
        });
        tvContent.setOnClickListener(ourClick);
        return rootView;
    }

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

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

onCreateDialog

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

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

onResume

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

    @Override
    public 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

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

    @Override
    public 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;
  }

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

    @Nullable
    @Override
    public 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() {
            @Override
            public void onClick(View v) {
                dismissAllowingStateLoss();
            }
        });
        tvContent.setOnClickListener(ourClick);
        return rootView;
    }

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

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

    @Override
    public 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);
        }
    }

    @Override
    public 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("动态回传要监听的内容即可");
  });

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

S32K3 工具篇2:如何在S32DS中使用Segger JLINK下载

S32K3 工具篇2:如何在S32DS中使用Segger JLINK下载 一, S32DS中JLINK下载1.1 Segger JLINK 驱动1.2 S32DS JLINK驱动路径配置1.3 S32DS JLINK debug configuration1.4 S32DS JLINK debug S32K3板子结果 二, JLINK驱动实现S32K344代码下载2.1 …

【Sublime】Sublime Text 中运行终端

Sublime Text 本身并不是一个终端仿真器,可以使用插件来在 Sublime Text 中集成终端功能。最常用的插件之一是“Terminal”。 使用“Terminal”插件在 Sublime Text 中启动终端 以下是安装和使用该插件的步骤: 安装 Package Control: 如果你…

【IJCAI2024】LeMeViT: Efficient Vision Transformer with Learnable Meta Tokens

【IJCAI2024】LeMeViT: Efficient Vision Transformer with Learnable Meta Tokens for Remote Sensing Image Interpretation 论文:https://arxiv.org/abs/2405.09789 代码:https://github.com/ViTAE-Transformer/LeMeViT 由于相邻像素和图像块之间的高…

Thermo Fisher Scientific赛默飞检测扫描架IPC电路板维修WAH402290

美国Thermo Fisher赛默飞世尔光谱仪IS10 IS5光谱仪主板维修iCAP6000/iCAP7000/iCAP7400;热电质朴分析仪电路板维修 公司仪器维修设备备有三相交流电源,变频电源,无油空压气源,标准化的维修平台、电子负载,耐压测试仪、老化台车和各…

云动态摘要 2024-06-28

给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 [新客专享]WeData 限时特惠 腾讯云 2024-06-21 数据分类分级管理,构建数据安全屏障 ,仅需9.9元! 云服务器ECS试用产品续用 阿里云 2024-04-14 云服务器…

量化投资 日周月报 2024-06-28

文章 深度学习在量化交易中的应用:在BigQuant量化交易平台的文章中,探讨了深度学习在量化交易中,特别是在因子挖掘方面的应用。文章提到,随着传统线性模型的潜力逐渐枯竭,非线性模型逐渐成为量化交易的主要探索方向。深度学习因其对非线性关系的拟合能力,在量化交易中展现…

华为面试题及答案——机器学习(二)

21. 如何评价分类模型的优劣? (1)模型性能指标 准确率(Accuracy): 定义:正确分类的样本数与总样本数之比。适用:当各类样本的数量相对均衡时。精确率(Precision): 定义:预测为正类的样本中实际为正类的比例。适用:当关注假阳性错误的成本较高时(例如垃圾邮件检测…

firewalld(3)zone配置

简介 前面文章我们已经介绍了firewalld的安装,配置文件介绍、简单的规则查询,本篇文章主要介绍zone的配置。前面我们介绍了firewalld默认的zone和不同zone的功能,下面我们就直接进入zone的具体配置使用。 配置zone的方式 图形配置工具 firewall-config: 这是一个图形…

SAP PP学习笔记24 - 生产订单(制造指图)的创建

上面两章讲了生产订单的元素。 SAP PP学习笔记22 - 生产订单(制造指图)的元素1-CSDN博客 SAP PP学习笔记23 - 生产订单(制造指图)的元素2 - 决济规则(结算规则)-CSDN博客 这一章讲生产订单的创建。比如 - 生产订单的流程&#…

Unity Animator 运行时修改某个动画状态的播放速度

1.添加动画参数,选择需要动态修改速度的动画状态 2.在属性面板种设置速度倍速参数

three.js场景三元素

three.js是一个基于WebGL的轻量级、易于使用的3D库。它极大地简化了WebGL的复杂细节,降低了学习成本,同时提高了性能。 three.js的三大核心元素: 场景(Scene) 场景是一个三维空间,是所有物品的容器。可以将…

Java集合实例

一、什么是Java集合实例: 指的是在 Java 程序中创建和使用的集合对象,这些对象用于存储和操作数据。Java 集合框架提供了一系列的接口和实现类,用于管理不同类型的数据集合。 二、Java集合的主要实例类型: 1. List(列…

uni-app uni-data-picker级联选择器无法使用和清除选中的值

出现问题&#xff1a; 使用点击右边的叉号按钮无法清除已经选择的uni-data-picker值 解决办法&#xff1a; 在uni-app uni-data-picker使用中&#xff0c;要添加v-model&#xff0c;v-model在官网的示例中没有体现&#xff0c;但若不加则无法清除。 <uni-data-picker v-m…

激光与相机融合标定汇总:提升融合算法的精度与可靠性(附github地址)

前言 随着科技的飞速发展&#xff0c;激光技术与相机技术的融合已成为推动智能化影像发展的重要力量。这种融合不仅提高了成像的精度和效率&#xff0c;还为相关行业带来了革命性的变革。在这篇博客中&#xff0c;我们将深入探讨激光与相机融合标定的原理及其在各个领域的应用…

关于bim数字孪生threejs中使用glb文件大小优化及加载慢的说明(笔记)

在用three.js开发的时候发现&#xff0c;稍微大一点的glb或者fbx文件加载的时候很慢很卡 一直不理解这个卡和慢取决于哪些条件&#xff0c;下面来详细说一下 1、关于模型 不是越大加载越卡顿&#xff0c;而是却决于三角面数量&#xff0c;当累计三角面数量达到3000万时会出现明…

C语言基础——操作符

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 个人主页&#xff1a;励志不掉头发的内向程序员&#xff1b; 专栏主页&#xff1a;C语言基础&#xff1b; 文章目录 前言 一、操作符的分类 二、二进制和进制转换 2.1 二进制转十进制 2.1.1 十…

FreeRTOS信号量和互斥量

信息量 简介 信号量是一种解决同步问题的机制&#xff0c;可以实现对共享资源的有序访问。 前面介绍的队列(queue)可以用于传输数据&#xff1a;在任务之间、任务和中断之间。 消息队列用于传输多个数据&#xff0c;但是有时候我们只需要传递状态&#xff0c;这个状态值需要用…

并发编程基础概念

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

破解对LabVIEW的偏见

LabVIEW被广泛应用于科学研究、工程测试和自动化控制领域&#xff0c;具有专业性和高效的开发能力。尽管有人对其存在偏见&#xff0c;认为不如C语言&#xff0c;但LabVIEW的图形化编程、强大集成能力、丰富社区支持和专业功能&#xff0c;使其在许多实际应用中表现出色。通过多…

山东大学-科技文献阅读与翻译(期末复习)(选择题+翻译)

目录 选择题 Chapter1 1.which of the following is not categorized as scientific literature 2.Which of the followings is defined as tertiary(三级文献) literature? 3.Which type of the following international conferences is listed as Number one conference…