我们使用了哪些Flutter 三方库(二)

一、背景

前面写了《我们使用了哪些 Flutter 三方库》,但是仅介绍了工程使用的一部分Flutter三方库,本篇继续介绍工程中使用Flutter 三方库。

二、Hive、hive_flutter

轻量级高性能键值数据库,提供比SQLite更快的本地存储方案

Pub地址:pub.dev/packages/hi...

  • ✅ 高性能键值存储:基于 Dart 原生实现,比 SQLite 更快
  • ✅ 零依赖:不依赖平台原生代码,纯 Dart 实现
  • ✅ 类型安全:通过泛型支持自动序列化/反序列化
  • ✅ 跨平台支持:iOS/Android/Web/Desktop(全平台兼容)
  • ✅ 加密支持:内置 AES-256 加密(需 hive_flutter 扩展)

初始化:

dart 复制代码
wait Hive.initFlutter();

获取box对象

csharp 复制代码
await Hive.openBox('xxx')

读取、写入

dart 复制代码
// 写入数据
box.put('name', 'Alice');
box.put('age', 25);

// 读取数据
String name = box.get('name');
int age = box.get('age', defaultValue: 0);

三、auto_size_text

智能文本尺寸调节组件,自动缩放文字以适应可用空间

  • ✅ 智能缩放:自动调整字体大小填满容器
  • ✅ 多行支持:完美处理文本换行与省略号
  • ✅ 性能优化:内置文本缓存避免重复计算
  • ✅ 精细控制:支持最小/最大字体尺寸限制
  • ✅ 无缝集成:完全兼容所有Text组件的属性

主要是使用其 AutoSizeText 这个Widget,工程中直接拿来用了没啥封装。

四、url_launcher

跨平台URL启动器,一键调用系统浏览器/地图/电话/邮件等原生功能

  • ✅ 多协议支持:
    • http(s):// → 打开网页
    • tel:// → 拨打电话
    • sms:// → 发送短信
    • mailto:// → 调用邮件客户端
    • geo:// → 打开地图应用
  • ✅ 启动模式控制:
    • 应用内WebView(WebView插件配合使用)
    • 系统默认浏览器
    • 强制使用Safari/Chrome
  • ✅ 结果回调:检测功能是否可用及执行结果

核心方法只有一个:launchUrl

其他方法还有:

  • canLaunchUrl
  • closeInAppWebView
  • supportsLaunchMode
  • supportsCloseForLaunchMode

需要主要的是在不同的平台可能存在表现差异

五、flutter_linkify

智能文本链接解析器,自动识别文本中的URL/邮箱/电话并转为可点击链接

  • ✅ 支持正则表达式自定义匹配规则
  • ✅ 内置人类可读URL展示优化(如显示"google.com"而非"www.google.com")
  • ✅ 完全兼容Text的所有样式属性

基本用法

dart 复制代码
Linkify(
  text: "访问 https://flutter.dev 或联系 support@email.com",
  onOpen: (link) => launchUrl(Uri.parse(link.url)), // 配合url_launcher使用
  options: LinkifyOptions(humanize: true), // 自动简化URL显示
)

可以继承 Linkifier ,来自定义协议解析规则,如我们工程中定义的解析规则:

dart 复制代码
final _urlRegex = RegExp(
  r'^(.*?)((?:https?:\/\/|www\.)[^\s/$.?#].[^\s]*)',
  caseSensitive: false,
  dotAll: true,
);

final _looseUrlRegex = RegExp(
  r'''^(.*?)((https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//="'`]*))''',
  caseSensitive: false,
  dotAll: true,
);

final _protocolIdentifierRegex = RegExp(
  r'^(https?:\/\/)',
  caseSensitive: false,
);

class UrlLinkifier extends Linkifier {
  const UrlLinkifier();

  @override
  List<LinkifyElement> parse(elements, options) {
    final list = <LinkifyElement>[];

    for (var element in elements) {
      if (element is TextElement) {
        var match = options.looseUrl
            ? _looseUrlRegex.firstMatch(element.text)
            : _urlRegex.firstMatch(element.text);

        if (match == null) {
          list.add(element);
        } else {
          final text = element.text.replaceFirst(match.group(0)!, '');

          if (match.group(1)?.isNotEmpty == true) {
            list.add(TextElement(match.group(1)!));
          }

          if (match.group(2)?.isNotEmpty == true) {
            var originalUrl = match.group(2)!;
            var originText = originalUrl;
            String? end;

            if ((options.excludeLastPeriod) &&
                originalUrl[originalUrl.length - 1] == ".") {
              end = ".";
              originText = originText.substring(0, originText.length - 1);
              originalUrl = originalUrl.substring(0, originalUrl.length - 1);
            }

            var url = originalUrl;

            if (!originalUrl.startsWith(_protocolIdentifierRegex)) {
              originalUrl = (options.defaultToHttps ? "https://" : "http://") +
                  originalUrl;
            }

            if ((options.humanize) || (options.removeWww)) {
              if (options.humanize) {
                url = url.replaceFirst(RegExp(r'https?://'), '');
              }
              if (options.removeWww) {
                url = url.replaceFirst(RegExp(r'www\.'), '');
              }

              list.add(UrlElement(
                originalUrl,
                url,
                originText,
              ));
            } else {
              list.add(UrlElement(originalUrl, null, originText));
            }

            if (end != null) {
              list.add(TextElement(end));
            }
          }

          if (text.isNotEmpty) {
            list.addAll(parse([TextElement(text)], options));
          }
        }
      } else {
        list.add(element);
      }
    }

    return list;
  }
}

/// Represents an element containing a link
class UrlElement extends LinkableElement {
  UrlElement(String url, [String? text, String? originText])
      : super(text, url, originText);

  @override
  String toString() {
    return "LinkElement: '$url' ($text)";
  }

  @override
  bool operator ==(other) => equals(other);

  @override
  int get hashCode => Object.hash(text, originText, url);

  @override
  bool equals(other) => other is UrlElement && super.equals(other);
}

六、flutter_slidable

强大的滑动操作组件,为列表项添加左/右滑出菜单,支持多种交互手势和动画效果

  • ✅ 支持左右双向滑动操作
  • ✅ 内置6种动作面板动画效果
  • ✅ 可自定义滑动阈值和灵敏度
  • ✅ 完美兼容ScrollView各种场景

主要就是使用 Slidable 组件。

示例代码(工程中比较负责,这里贴一个示例)

less 复制代码
Slidable(
  endActionPane: ActionPane(
    motion: const ScrollMotion(), // 滑动动画类型
    children: [
      SlidableAction(
        icon: Icons.delete,
        backgroundColor: Colors.red,
        onPressed: (_) => _deleteItem(context),
      ),
      SlidableAction(
        icon: Icons.share,
        backgroundColor: Colors.blue,
        onPressed: (_) => _shareItem(context),
      ),
    ],
  ),
  child: ListTile(title: Text('可滑动的列表项')),
)

同时Slidable还可以通过自定义ActionPane实现弧形菜单、动态宽度等高级效果。

七、time_machine

强大的日期时间处理库,提供时区、日历、周期计算等高级功能

  • ✅ 完整的时区数据库(IANA TZDB)
  • ✅ 人类友好的时间差计算(如"2小时前")
  • ✅ 支持多种日历系统(ISO、Gregorian等)
  • ✅ 不可变类型设计(线程安全)
dart 复制代码
final now = LocalClock().today(); // 获取当前日期
final birthday = LocalDate(2025, 5, 25);

// 计算时间差
final period = now.periodUntil(birthday); 
print('距离生日还有: ${period.months}月${period.days}天');

在我们的工程中主要是使用了:DayOfWeek

八、flutter_keyboard_visibility

实时监听软键盘显示/隐藏状态,完美解决键盘遮挡输入框问题

  • ✅ 全平台支持(Android/iOS/Web/Desktop)
  • ✅ 毫秒级响应键盘状态变化
  • ✅ 支持多监听器订阅模式
  • ✅ 完美兼容单页面多表单场景

在我们工程中使用的是 KeyboardVisibilityBuilder ,组件级别的监听方案,示例代码:

less 复制代码
KeyboardVisibilityBuilder(
  builder: (context, isKeyboardVisible) {
    return AnimatedContainer(
      height: isKeyboardVisible ? 60 : 200,
      duration: Duration(milliseconds: 300),
      child: TextField(),
    );
  },
)

九、extended_text_field

高度可定制的富文本输入框,支持@提及、话题标签、自定义背景等高级功能

  • ✅ 原生TextField的所有功能+扩展能力
  • ✅ 支持富文本特殊内容高亮(如#话题、@用户)
  • ✅ 自定义文本背景/下划线样式
  • ✅ 精确控制光标位置和选择范围

示例代码

dart 复制代码
ExtendedTextField(
  specialTextSpanBuilder: MySpecialTextSpanBuilder(), // 自定义解析器
  controller: _controller,
  decoration: InputDecoration(hintText: "输入@提及用户或#话题"),
)

十、总结

以上在上一篇的基础上又介绍了几个三方库,希望能够给读者带来一些额外的思考。

相关推荐
小蜜蜂嗡嗡3 小时前
flutter封装vlcplayer的控制器
前端·javascript·flutter
AirDroid_cn3 小时前
OPPO手机怎样被其他手机远程控制?两台OPPO手机如何相互远程控制?
android·windows·ios·智能手机·iphone·远程工作·远程控制
尊治3 小时前
手机电工仿真软件更新了
android
杂雾无尘4 小时前
开发者必看,全面解析应用更新策略,让用户无法拒绝你的应用更新!
ios·xcode·swift
xiangzhihong86 小时前
使用Universal Links与Android App Links实现网页无缝跳转至应用
android·ios
车载应用猿6 小时前
基于Android14的CarService 启动流程分析
android
没有了遇见7 小时前
Android 渐变色实现总结
android
Digitally7 小时前
如何将iPhone备份到Mac/MacBook
macos·ios·iphone
帅次8 小时前
【iOS设计模式】深入理解MVC架构 - 重构你的第一个App
ios·swiftui·objective-c·iphone·swift·safari·cocoapods
雨白9 小时前
Jetpack系列(四):精通WorkManager,让后台任务不再失控
android·android jetpack