Flutter标签管理插件flutter_taggable的使用

Flutter标签管理插件flutter_taggable的使用

允许用户提及其他用户、插入话题标签以及其他实体的标签。此轻量级包提供了一种数据库友好的格式,便于存储和解析标签。该包高度可定制,并且可以与标准的TextField小部件一起使用。

演示视频

动机

许多包允许在文本字段中提及或标记用户,但并非所有包都能以一种便于检索和解析的方式来存储这些标签。考虑以下场景:

用户在评论中写入并发布“@Ada Lovelace, 检查一下这个包!”假设后端服务器需要解析这条评论来向Ada发送通知。如果将评论原样存储,会出现两个问题:

  1. 标签在哪里结束?是[@Ada](/user/Ada)[@Ada](/user/Ada) Lovelace还是[@Ada](/user/Ada) Lovelace, 检查?很难确定确切的标签。
  2. 如果Ada更改了她的用户名为[@Ada](/user/Ada) King,则评论将不再提及她。

然而,任何可标记的实体通常都有一个唯一标识符,例如用户ID。此包允许标记用户,使得前端显示对用户友好,同时提供一种数据库友好的格式,便于轻松解析和检索。

特性

  • 轻量级:此包可以与标准的TextField小部件一起使用——你只需将TextEditingController替换为TagTextEditingController
  • 对终端用户友好:控制器处理标记逻辑,因此你可以专注于UI。例如,退格键删除整个标签,而不是仅删除一个字符。
  • 可定制的标签格式:指定前端格式(如[@Ada](/user/Ada) Lovelace)和后端格式(如@123)。此包还可以支持多种类型的标记(如[@Ada](/user/Ada) Lovelace#MyTrendingTopic,参见上面的视频)。
  • 可定制的搜索功能:指定包应如何搜索标签,以及选项应如何显示。
  • 类型注解:给TagTextEditingController添加类型以提高类型安全性和代码完成度,当你定义回调时。

开始使用

该包假定你的‘可标记’数据有三种形式:

  1. 代表可标记实体的数据类对象。
  2. 可以在UI中显示的此实体表示形式。
  3. 可以存储在数据库中的此实体表示形式。

示例中,我们使用以下类来表示一个可标记实体:

class Taggable {
  const Taggable({required this.id, required this.name, required this.icon});

  final String id;
  final String name;
  final IconData icon;
}

id是可标记实体的唯一标识符,name是在UI中显示的字符串。将其与WhatsApp进行比较,可标记实体将是用户,id将是用户的电话号码,name将是用户的名字。

该包支持具有多种类型的可标记实体。为了使代码更简洁,我们建议为每种类型的可标记实体创建一个扩展Taggable的类。例如:

class User extends Taggable {
  const User(
      {required super.id, required super.name, super.icon = Icons.person});
}

class Topic extends Taggable {
  const Topic(
      {required super.id, required super.name, super.icon = Icons.topic});
}

或者,您可以使Taggable类具有返回前端和后端表示形式的抽象方法,由子类实现。

使用

安装

通过以下命令将包添加到项目中:

flutter pub add flutter_taggable

基本用法

要使用该包,你需要将默认的TextEditingController替换为TagTextEditingController并指定几个参数;

import 'package:flutter/material.dart';
import 'package:flutter_taggable/flutter_taggable.dart';

class TaggableExample extends StatefulWidget {
  @override
  _TaggableExampleState createState() => _TaggableExampleState();
}

class _TaggableExampleState extends State<TaggableExample> {
  late TagTextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TagTextEditingController<Taggable>(
    searchTaggables: searchTaggables,
    buildTaggables: buildTaggables,
    toFrontendConverter: (taggable) => taggable.name,
    toBackendConverter: (taggable) => taggable.id,
    tagStyles: {
      '@': const TextStyle(color: Colors.blue),
      '#': const TextStyle(color: Colors.green),
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Taggable Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: TextField(
          controller: _controller,
          decoration: InputDecoration(
            hintText: 'Type @ to tag a user or # to tag a topic',
          ),
        ),
      ),
    );
  }
}

注意如何将控制器类型注解为Taggable类。创建TagTextEditingController时需要指定多个参数。展开以下部分了解更多信息。

参数

FutureOr<Iterable<T>> Function(String prefix, String? query) searchTaggables

此函数在用户输入标签时被调用。它应该返回匹配查询的可标记实体列表。prefix参数是用户开始标签所键入的字符,query参数是用户在前缀后键入的文本。例如,如果用户键入[@Ada](/user/Ada)prefix将是@query将是Ada。返回类型为FutureOr是因为该函数可以是同步的(如果数据已经可用),也可以是异步的(如果数据需要从某个地方获取)。

Future<T?> Function(FutureOr<Iterable<T>> taggables) buildTaggables

此函数接受匹配查询的可标记实体列表,并构建这些实体的UI表示形式。在示例中,使用OverlayEntry来将选项显示为列表。因为用户通常通过点击选择选项,所以返回类型是一个Future。示例使用Completer来返回所选的可标记实体,因为OverlayEntry不直接返回值。

String Function(T taggable) toFrontendConverter

此函数将可标记实体转换为将在UI中显示的字符串。在示例中,我们使用Taggable类的name字段。

String Function(T taggable) toBackendConverter

此函数将可标记实体转换为将在数据库中存储的字符串。在示例中,我们使用Taggable类的id字段。

List<TagStyle> tagStyles

此列表指定了用户可以标记实体的方式。每个TagStyle对象有一个用于触发标记的prefix(默认为@),以及一个指定文本字段中标记TextStylestyle。此外,它还有一个regExp参数,用于指定可以在文本字段中找到标记的正则表达式。任何紧跟在prefix之后且匹配regExp的字符串都将被视为标记。

转换

在以下三个过程中,可标记实体会被转换:

  1. 保存带有标签的文本:当需要保存包含标签的文本时,可以使用TagTextEditingControllertextInBackendFormat获取器来获取后端格式的文本。不要使用text获取器,因为内部文本表示形式与前端和后端格式都不相同。
  2. 填充文本字段:当你有一段文本处于后端格式并希望用它填充文本字段时,可以使用TagTextEditingControllersetInitialText方法。除了文本外,还需要提供将后端格式转换为可标记实体的backendToTaggable函数。此函数具有以下签名:
FutureOr<T?> Function(String prefix, String backendString) backendToTaggable

更多关于Flutter标签管理插件flutter_taggable的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter标签管理插件flutter_taggable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_taggable插件的一个基本示例。这个插件允许你轻松地在应用中实现标签管理功能。

首先,你需要在你的pubspec.yaml文件中添加flutter_taggable依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_taggable: ^最新版本号  # 请替换为当前最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter应用中,你可以按照以下步骤使用flutter_taggable

  1. 导入包

在你的Dart文件中导入flutter_taggable包:

import 'package:flutter_taggable/flutter_taggable.dart';
  1. 创建标签数据

定义你想要显示的标签数据。这里我们用一个简单的字符串列表来模拟标签:

List<String> tags = ['Flutter', 'Dart', 'Mobile Development', 'Cross-Platform'];
  1. 使用TagContainer小部件

在你的UI中使用TagContainer小部件来显示和管理标签。以下是一个简单的示例:

import 'package:flutter/material.dart';
import 'package:flutter_taggable/flutter_taggable.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Taggable Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TagPage(),
    );
  }
}

class TagPage extends StatefulWidget {
  @override
  _TagPageState createState() => _TagPageState();
}

class _TagPageState extends State<TagPage> {
  List<String> tags = ['Flutter', 'Dart', 'Mobile Development', 'Cross-Platform'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Taggable Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: TagContainer(
          tags: tags,
          onDeleted: (tag) {
            setState(() {
              tags.remove(tag);
            });
          },
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(16),
            color: Colors.grey[200],
          ),
          textStyle: TextStyle(color: Colors.black),
          alignment: WrapAlignment.start,
          spacing: 4.0,
          runSpacing: 4.0,
          deleteIcon: Icon(
            Icons.close,
            color: Colors.red,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 这里可以添加添加新标签的逻辑
          setState(() {
            tags.add('New Tag'); // 简单示例:添加一个新标签
          });
        },
        tooltip: 'Add Tag',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个TagContainer小部件来显示标签。当用户点击删除图标时,标签会从列表中移除。同时,我们提供了一个浮动操作按钮(FAB),用于添加新标签(在这个例子中,只是简单地添加了一个静态的新标签字符串)。

你可以根据自己的需求进一步自定义标签的样式、添加逻辑等。希望这个示例能帮助你开始使用flutter_taggable插件!

回到顶部