Flutter芯片输入自动完成插件chips_input_autocomplete的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter芯片输入自动完成插件 chips_input_autocomplete 的使用

🚀 特性

  • 动态芯片创建: 用户可以输入来动态创建芯片。适用于标签、联系人或任何分类。
  • 自动完成建议: 根据预定义选项提供用户输入时的建议。
  • 可定制外观: 完全控制芯片的外观,包括背景色、边框和文本颜色。
  • 表单集成: 轻松与表单集成,允许验证和提交芯片数据。
  • 广泛自定义: 除了样式,还可以自定义行为,如选择时添加芯片、限制选择等。

🏁 入门

要开始使用 chips_input_autocomplete,请查看 安装使用方法。详细的文档可以在 API 参考 中找到。

🛠️ 使用方法

要在 Flutter 项目中使用 chips_input_autocomplete,请按照以下步骤操作:

基本芯片输入

此示例演示如何创建一个基本的芯片输入字段,用户可以输入来动态创建芯片。

const List<String> yourOptionsList = ['Option 1', 'Option 2', 'Option 3'];

ChipsInputAutocomplete(
  options: yourOptionsList,
)

验证输入

仅允许匹配预定义选项的芯片。此示例使用验证方法确保只有有效选项被添加为芯片。

ChipsInputAutocomplete(
  options: yourOptionsList,
  validateInputMethod: (String? input) {
    if (yourOptionsList.contains(input)) {
      return null; // 输入有效
    } else {
      return '仅允许预定义的选项'; // 输入无效
    }
  },
)

获取芯片数据

使用控制器获取选中的芯片数据。

final ChipsAutocompleteController controller = ChipsAutocompleteController();

ChipsInputAutocomplete(
  controller: controller,
)

// 获取选中的芯片数据
List<String> selectedChips = controller.chips; // selectedChips = ['Chiptext 1', 'Chiptext 2']

异步获取选项

使用控制器管理异步选项。此示例从 API 获取选项并设置在控制器中。

final ChipsAutocompleteController controller = ChipsAutocompleteController();

@override
void initState() {
  getTagsOptions();
  super.initState();
}

Future<void> getTagsOptions() async {
  controller.options = await fetchTags();
}

ChipsInputAutocomplete(
  controller: controller,
)

更多详细示例和用法,请参阅 pub.dev 示例

⚙️ 使用示例

以下是 chips_input_autocomplete 小部件的各种配置和行为示例。当前的外观请参阅 pub.dev 示例

Basic Demo Demo add on selection Demo only options allowed Demo async options fetched

🧷 参数

基本配置

  • controller: 管理芯片、自动完成选项和文本字段。
  • options: 自动完成选项的字符串列表。也可以通过控制器设置。
  • createCharacter: 触发芯片创建的字符。默认为 ,
  • placeChipsSectionAbove: 确定芯片部分是否位于文本字段上方/左侧或下方/右侧。

芯片外观

  • secondaryTheme: 当为 true 时,使用次级主题的芯片。基于 Material Design 3 的选定芯片主题。
  • chipTheme: 芯片的主题。默认为 Material Design 3。更多详情请参阅 ChipThemeData
  • deleteIcon: 删除芯片的图标。默认为关闭图标。可以设置为 null 以移除。
  • chipClipBehavior: 芯片的裁剪行为。默认为 Clip.none
  • deleteButtonTooltipMessage: 删除按钮的提示消息。默认为 Delete

文本字段外观和配置

  • focusNode: 文本字段的 FocusNode
  • decorationTextField: 文本字段的样式。
  • keyboardType: 文本字段的键盘类型。
  • enableSuggestions: 是否显示建议。
  • showCursor: 是否显示光标。
  • cursorWidth: 光标的宽度。
  • cursorColor: 光标的颜色。
  • cursorRadius: 光标的半径。
  • cursorHeight: 光标的高度。

容器外观

  • widgetContainerDecoration: 主小部件容器的装饰。
  • paddingInsideWidgetContainer: 主小部件容器内的填充。
  • spacing: 芯片之间的间距。默认为 5.0
  • runSpacing: 芯片行之间的间距。如果未设置,默认为 spacing
  • optionsMaxWidth: 选项视图的最大宽度。默认为文本字段的宽度。

其他配置

  • initialChips: 初始显示的芯片。
  • autoFocus: 小部件是否自动聚焦。
  • formKey: 用于访问或验证表单外部的小部件的表单键。
  • validateInputMethod: 验证方法,返回字符串表示输入无效。null 表示始终有效。
  • validateChipsMethod: 验证方法,返回字符串表示所有芯片无效。null 表示始终有效。
  • autovalidateMode: 表单的自动验证模式。默认为 AutovalidateMode.disabled
  • enabled: 小部件和文本字段是否启用。
  • addChipOnSelection: 选择选项时添加芯片。如果为 false,则将选项添加到文本字段。
  • showClearButton: 是否显示清除 IconButton
  • clearWithConfirm: 清除所有芯片时是否显示确认对话框。
  • eraseKeyLabel: 用于删除芯片的键标签。默认为退格键。
  • showOnlyUnselectedOptions: 是否仅显示未选择的选项。默认为 true

回调和事件处理

  • onChanged: 芯片值更改时的回调。
  • onChangedTextField: 文本字段更改时的回调。
  • onEditingComplete: 编辑完成时的回调。
  • onSaved: 表单保存时的回调。
  • onChipDeleted: 芯片删除时的回调,包含芯片内容和索引。
  • onChipAdded: 芯片添加时的回调,包含芯片内容。
  • onChipsCleared: 所有芯片清除时的回调。
  • useDefaultOnChipDeleted: 是否使用默认的 onChipDeleted 方法。可以设置为 false 以实现不同的逻辑。例如,当芯片从不同来源更新时。
  • useDefaultOnChipAdded: 是否使用默认的 onChipAdded 方法。可以设置为 false 以实现不同的逻辑。例如,当芯片从不同来源更新时。
  • useDefaultOnChipsCleared: 是否使用默认的 onChipsCleared 方法。可以设置为 false 以实现不同的逻辑。例如,当芯片从不同来源更新时。

🧑‍💻 作者

@BruckCode
@JohannesPauli

示例代码

以下是一个完整的示例代码,展示了如何在 Flutter 应用中使用 chips_input_autocomplete 插件。

/*
@Author: Johannes Pauli
@License: MIT
*/

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:chips_input_autocomplete/chips_input_autocomplete.dart';

void main() {
  runApp(const FlutterDemo());
}

class FlutterDemo extends StatelessWidget {
  const FlutterDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final ChipsAutocompleteController controllerExampleBasic =
      ChipsAutocompleteController();
  String chipsOutputExampleBasic = '';

  final ChipsAutocompleteController controllerExampleSecondaryTheme =
      ChipsAutocompleteController();
  String chipsOutputExampleSecondaryTheme = '';

  final ChipsAutocompleteController controllerExampleInsertOnSelect =
      ChipsAutocompleteController();
  String chipsOutputExampleInsertOnSelect = '';

  final ChipsAutocompleteController controllerExampleOnlyOptions =
      ChipsAutocompleteController();
  String chipsOutputExampleOnlyOptions = '';

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      controllerExampleBasic.addListener(() {
        setState(() {
          chipsOutputExampleBasic = controllerExampleBasic.chips.join(', ');
        });
      });
      controllerExampleSecondaryTheme.addListener(() {
        setState(() {
          chipsOutputExampleSecondaryTheme =
              controllerExampleSecondaryTheme.chips.join(', ');
        });
      });
      controllerExampleInsertOnSelect.addListener(() {
        setState(() {
          chipsOutputExampleInsertOnSelect =
              controllerExampleInsertOnSelect.chips.join(', ');
        });
      });
      controllerExampleOnlyOptions.addListener(() {
        setState(() {
          chipsOutputExampleOnlyOptions =
              controllerExampleOnlyOptions.chips.join(', ');
        });
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Chips Input Autocomplete Demo'),
      ),
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            children: [
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 500),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: Padding(
                            padding: const EdgeInsets.only(bottom: 16.0),
                            child: Text(
                              'Basic Example',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                          ),
                        ),
                        Text('Options: ${options.join(', ')}'),
                        ChipsInputAutocomplete(
                          controller: controllerExampleBasic,
                          options: options,
                        ),
                        Text('Selected: $chipsOutputExampleBasic'),
                      ],
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 500),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: Padding(
                            padding: const EdgeInsets.only(bottom: 16.0),
                            child: Text(
                              'Secondary Theme',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                          ),
                        ),
                        Text('Options: ${options.join(', ')}'),
                        ChipsInputAutocomplete(
                          controller: controllerExampleSecondaryTheme,
                          options: options,
                          secondaryTheme: true,
                        ),
                        Text('Selected: $chipsOutputExampleSecondaryTheme'),
                      ],
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 500),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: Padding(
                            padding: const EdgeInsets.only(bottom: 16.0),
                            child: Text(
                              'Add on selection',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                          ),
                        ),
                        Text('Options: ${options.join(', ')}'),
                        ChipsInputAutocomplete(
                          controller: controllerExampleInsertOnSelect,
                          options: options,
                          addChipOnSelection: true,
                        ),
                        Text('Selected: $chipsOutputExampleInsertOnSelect'),
                      ],
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 500),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: Padding(
                            padding: const EdgeInsets.only(bottom: 16.0),
                            child: Text(
                              'Only options allowed',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                          ),
                        ),
                        Text('Options: ${options.join(', ')}'),
                        ChipsInputAutocomplete(
                          controller: controllerExampleOnlyOptions,
                          options: options,
                          validateInputMethod: (String? input) {
                            if (options.contains(input)) {
                              return null; // 输入有效
                            } else {
                              return '仅允许预定义的选项'; // 输入无效
                            }
                          },
                        ),
                        Text('Selected: $chipsOutputExampleOnlyOptions'),
                      ],
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ConstrainedBox(
                    constraints: const BoxConstraints(maxWidth: 500),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Align(
                          alignment: Alignment.centerLeft,
                          child: Padding(
                            padding: const EdgeInsets.only(bottom: 16.0),
                            child: Text(
                              'Async fetched options',
                              style: Theme.of(context).textTheme.titleLarge,
                            ),
                          ),
                        ),
                        FutureBuilder<List<String>>(
                          future: fetchTags(),
                          builder: (context, snapshot) {
                            if (snapshot.connectionState == ConnectionState.waiting) {
                              return const CircularProgressIndicator();
                            } else if (snapshot.hasError) {
                              return Text('Error: ${snapshot.error}');
                            } else {
                              return ChipsInputAutocomplete(
                                controller: controllerExampleBasic,
                                options: snapshot.data ?? [],
                              );
                            }
                          },
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<List<String>> fetchTags() async {
    // 模拟从 API 获取选项
    await Future.delayed(Duration(seconds: 2));
    return ['Option 1', 'Option 2', 'Option 3'];
  }
}

希望这些示例和说明能帮助你更好地理解和使用 chips_input_autocomplete 插件!如果有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter芯片输入自动完成插件chips_input_autocomplete的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter芯片输入自动完成插件chips_input_autocomplete的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何在Flutter中使用chips_input_autocomplete插件的示例代码。这个插件允许你在Flutter应用中实现带有自动完成功能的芯片输入(chips input)。

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

dependencies:
  flutter:
    sdk: flutter
  chips_input_autocomplete: ^x.y.z  # 请替换为最新版本号

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

接下来,在你的Flutter应用中,你可以按照以下方式使用这个插件:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Chips Input Autocomplete Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> suggestions = [
    'Apple',
    'Banana',
    'Cherry',
    'Date',
    'Elderberry',
    'Fig',
    'Grape',
    'Honeydew',
    'Kiwi',
    'Lemon'
  ];

  List<String> chips = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Chips Input Autocomplete Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ChipsInputAutocomplete<String>(
          decoration: InputDecoration(
            labelText: 'Select fruits',
            border: OutlineInputBorder(),
          ),
          keyboardType: TextInputType.text,
          suggestions: suggestions,
          onChipSubmitted: (chip) {
            setState(() {
              chips.add(chip);
            });
          },
          onChipDeleted: (chip, index) {
            setState(() {
              chips.removeAt(index);
            });
          },
          chipBuilder: (context, state, chip) {
            return Chip(
              label: Text(chip),
              onDelete: () => state.deleteChip(chip),
            );
          },
          initialValue: chips,
          findSuggestions: (String query) {
            if (query.isEmpty) {
              return [];
            }
            return suggestions.where((p) => p.toLowerCase().contains(query.toLowerCase())).toList();
          },
        ),
      ),
    );
  }
}

这个示例代码展示了如何使用chips_input_autocomplete插件来实现一个带有自动完成功能的芯片输入组件。以下是代码的关键点:

  1. 依赖项:在pubspec.yaml文件中添加chips_input_autocomplete插件的依赖项。
  2. 状态管理:在_MyHomePageState类中管理芯片列表的状态。
  3. 芯片输入组件:使用ChipsInputAutocomplete组件来创建芯片输入区域。
  4. 建议列表:通过suggestions属性提供自动完成的建议列表。
  5. 提交和删除芯片:通过onChipSubmittedonChipDeleted回调函数来处理芯片的提交和删除。
  6. 芯片构建:使用chipBuilder属性来定制芯片的外观。
  7. 自动完成逻辑:通过findSuggestions回调函数来实现自动完成的逻辑。

希望这个示例代码能帮助你更好地理解如何在Flutter中使用chips_input_autocomplete插件。

回到顶部