Flutter 知识集锦 | extension 拓展类方法

Dart 的拓展类方法已经支持很久了,之前忘了写篇文章介绍一下。最近写了几个拓展方法,借此机会,好好介绍一下 extension 关键字对类的拓展。


1. 从密文的字符串开始说起

比如现在有个需求:

将一个长度大于 4 的字符串,仅保留首尾两个字符,进行密文展示。

比如 1981462002 -> 19******02

很容易可以想到,定义一个 hide 方法,输入一个字符串,进行处理后,输出目标字符串。处理逻辑如下:

dart 复制代码
void main(){
  String num = "1981462002";
  String ret = hide(num);
  print(ret); // 19******02
}

String hide(String src){
  String p0 = src.substring(0, 2);
  String p1 = List.filled(src.length - 4, '*').join();
  String p2 = src.substring(src.length-2);
  return "$p0$p1$p2";
}

上面通过 hide(num) 来调用方法,获得结果字符串。但是这种全局方法单独放置比较零散,维护起来有点麻烦。Dart 中提供了 extension 关键字拓展类方法,可以为一个类附加额外的方法.

通过 extension [name] on [type] 的语法定义 type 类型的拓展方法。如下所示,拓展 String 类型时,将之前的 hide 逻辑放入其中即可。此时 hide 方法可以访问 String 类中的公开成员和方法:

dart 复制代码
extension TolyStringExt on String {
  String hide(){
    String p0 = substring(0, 2);
    String p1 = List.filled(length - 4, '*').join();
    String p2 = substring(length-2);
    return "$p0$p1$p2";
  }
}

这样 hide 成为 String 类型对象的成员方法,其优势在于:

  • 1. 可以以增强某类型功能为目的,将某个函数收编,提供居住场所,不至于流落在外。
  • 2. 通过类型访问方法来调用实现功能,语义性更好。IDE 有快捷提示,方便使用。
  • 3. 一般拓展方法,在书写上更加简洁,拓展的方法,可以共享复用。

下面对 hide 方法进行优化,支持自定义密文字符,首尾保留的长度,以及字符串长短的校验。你也可以封装其他关于字符串的实用方法,比如一些邮箱、密码正则的校验。

dart 复制代码
extension TolyStringExt on String {
  String hide({
    String fix = "*",
    int start = 2,
    int end = 2,
  }) {
    if (length <= start) {
      return this;
    }
    String p0 = substring(0, start);
    int hideCount = length - start - end;
    if (hideCount <= 0) {
      return p0.padRight(length, fix);
    }
    String p1 = List.filled(length - (start + end), fix).join();
    String p2 = substring(length - end);
    return "$p0$p1$p2";
  }
}

2. BuildContext 的拓展方法

Flutter 中 BuildContext 是一个非常重要对象,它作为 Element 的顶层接口,负责维护构建过程中的上下文信息,可以通过它来向上层查找元素节点、访问渲染对象。很多状态管理、路由的类库中,都可以看到对它复写的身影。这里以一个简单的 Snack 弹框为例,看一下对 BuildContext 的拓展。

成功 提醒

如下所示,这是以前对 Toast 的简单封装,使用静态方法来简化调用,将 BuildContext 作为入参传入其中。并提供三种颜色作为成功、失败、警告三种场景的背景色:

dart 复制代码
import 'package:flutter/cupertino.dart';

class Toast{
 static void success(BuildContext context,String msg){
   toast(context, Colors.green, msg);
  }

 static void error(BuildContext context,String msg){
    toast(context, Colors.red, msg);
  }

 static  void warning(BuildContext context,String msg){
    toast(context, Colors.orange, msg);
  }

 static void toast(BuildContext context,Color color,String msg){
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        backgroundColor: color, content: Text(msg)));
  }
}

方法调用如下:

dart 复制代码
Toast.warning(context,'当前领域秘钥未修改,无需提交');

可以通过拓展 BuildContext 来简化,将 toast 视为 BuildContext 的能力,在调用时将会更简洁:

dart 复制代码
import 'package:flutter/material.dart';

extension ToastContext on BuildContext {

  void toast(Color color, String msg) {
    ScaffoldMessenger.of(this).showSnackBar(
      SnackBar(backgroundColor: color, content: Text(msg)),
    );
  }

  void warning(String msg) => toast(Colors.orange, msg);

  void error(String msg) => toast(Colors.red, msg);

  void success(String msg) => toast(Colors.green, msg);
}

3. 其他三方库对 BuildContext 的拓展

provider 中的 read、 watch、select 等操作,是对 BuildContext 的拓展,可以更方便地通过上下文调用的方式访问提供器:

dart 复制代码
extension ReadContext on BuildContext {
  T read<T>() {
    return Provider.of<T>(this, listen: false);
  }
}

extension WatchContext on BuildContext {
  T watch<T>() {
    return Provider.of<T>(this);
  }
}


extension SelectContext on BuildContext {
    R select<T, R>(R Function(T value) selector) {...}
}

go_router 中的 push、pop、go 等一系列方法,也是对 BuildContext 的拓展,可以更方便的通过 BuildContext 对象触发方法,来操作路由的变化:


总的来看,拓展方法可以让作为入参的某个对象拥有 主动权,作为该类型的附加方法,可以达到简化调用的目的。不过拓展方法虽好,可不要贪杯哦,肆意的拓展,可能会使代码很难让别人读懂,这点和运算符的重载类似。以语义为准绳,不要为了炫技而覆写或拓展。那本文就到这里,谢谢观看 ~

相关推荐
杉氧1 小时前
状态管理变迁史:为什么我们放弃了 Redux 选择 Zustand?
android·前端·react native
三少爷的鞋5 小时前
别再靠 Code Review 守底线:我做了一个静态分析项目 RedLine
android
y = xⁿ13 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
2601_9620664915 小时前
【Sql Server】Update中的From语句,以及常见更新操作方式
android·java·数据库
用户693717500138421 小时前
曾经安卓开发人手一个的 EventBus,为什么现在没人爱用了?
android·android studio
九皇叔叔1 天前
MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引
android·adb
OriginCoding1 天前
用 AI Agent 协作完成一个 Android TOTP 应用:从需求边界到 v1.0.0
android·ai编程
杉氧1 天前
React 灵魂:深入剖析 Hooks 与副作用(Side Effects)陷阱
android·前端·react native
又见情义1 天前
RK3568 + RTL8211F 网络唤醒(WOL)功能适配全记录
android·网络·驱动开发
「、皓子~1 天前
海狸IM 2.1 正式发布
flutter·微服务·golang·electron·开源软件·im·海狸im