Flutter自动补全插件elastic_autocomplete的使用

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

Flutter自动补全插件elastic_autocomplete的使用

ElasticAutocomplete 是一个结合了 AutocompleteLocalStorage 的小部件。通过它,您可以轻松地实现自动补全功能,并且可以将数据存储在本地存储或内存中。

功能

  • 它可以通过 ElasticAutocompleteController 轻松处理选项列表,并通过 id 共享相同的选项。

    • 您可以在本地存储中存储数据,这些数据会一直保留,直到用户清理它们。
    • 您也可以仅在内存中(类似于会话存储)存储数据,这些数据会一直保留,直到程序终止。
    • 在生成候选时,您可以选择是否区分大小写。如果想自己生成候选,可以设置 contains 函数。
  • 可以通过 ElasticAutocompleteController 简单生成 fieldViewBuilderoptionsBuilder。但是,如果不使用控制器,也可以自行设置它们两个。

使用

示例:不使用控制器

您可以使用 optionsBuilder 控制选项列表。此外,还可以自行装饰 TextFormField

ElasticAutocomplete<String>(
  optionsBuilder: (TextEditingValue textEditingValue) {
    if (textEditingValue.text == '') {
      return const Iterable<String>.empty();
    }
    const List<String> options = [
      "app",
      "bar",
      "car"
    ];
    return options.where((String option) {
      return option.contains(textEditingValue.text);
    });
  },
  fieldViewBuilder: (BuildContext context,
      TextEditingController textEditingController,
      FocusNode focusNode,
      void Function() onFieldSubmitted) {
    return TextFormField(
      autofocus: true,
      // 必须在textFormField中设置controller, focusNode, 和onFieldSubmitted
      controller: textEditingController,
      focusNode: focusNode,
      onFieldSubmitted: (String value) {
        onFieldSubmitted();
      },
      decoration: const InputDecoration(
        border: OutlineInputBorder(),
      ));
  });

示例:使用控制器

使用 ElasticAutocompleteController 加载和设置选项列表非常方便。此外,也容易生成 optionsBuilderfieldViewBuilder。您可以在 ElasticAutocompleteController 中设置是否区分大小写来影响由控制器自动生成的 optionBuilder。默认情况下是区分大小写的。

class MyWidgetState extends State<MyWidget> {
  final _formKey = GlobalKey<FormState>();
  late FocusNode _node;
  late ElasticAutocompleteController<String> _elasticAutocompleteCtrl;
  late TextEditingController _textEditingCtrl;

  [@override](/user/override)
  void initState() {
    _node = FocusNode();
    _textEditingCtrl = TextEditingController();
    _elasticAutocompleteCtrl =
        ElasticAutocompleteController(id: 'example', caseSensitive: false);
    super.initState();
  }

  [@override](/user/override)
  void dispose() {
    _textEditingCtrl.dispose();
    _node.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElasticAutocomplete<String>(
                controller: _elasticAutocompleteCtrl,
                // 使用由控制器生成的optionsBuilder
                optionsBuilder: _elasticAutocompleteCtrl.optionsBuilder,
                // 使用由控制器生成的fieldViewBuilder
                fieldViewBuilder: _elasticAutocompleteCtrl.fieldViewBuilder(
                    decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                )),
                // 使用textEditingController获取TextFormField中的值
                textEditingController: _textEditingCtrl,
                // 设置textEditingController时,同时设置focusNode
                focusNode: _node),
            // 将新值存储到内存单元中
            ElevatedButton(
                onPressed: () async {
                  if (_formKey.currentState?.validate() ?? false) {
                    String val = _textEditingCtrl.text;
                    // 清空文本输入字段
                    _textEditingCtrl.clear();
                    // 存储到内存单元
                    await _elasticAutocompleteCtrl.store(val);
                    print(val);
                  }
                },
                child: const Text("发送")),
            // 清除内存单元中的所有选项
            ElevatedButton(
              onPressed: () {
                _elasticAutocompleteCtrl.clear();
              },
              child: const Text("清除"),
            ),
          ],
        ));
  }
}

文档

示例代码

以下是完整的示例代码:

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // 此小部件是您的应用程序的根
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: const MyHomePage(title: 'ElasticAutocomplete'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(title),
        ),
        body: Scrollbar(
          child: SingleChildScrollView(
              padding: const EdgeInsets.all(10),
              child: Center(
                  child: Container(
                constraints: const BoxConstraints(maxWidth: 400),
                child: const Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Padding(
                        padding: EdgeInsets.symmetric(vertical: 15),
                        child: Text(
                          '示例1 构建选项而不使用控制器',
                          style: TextStyle(fontSize: 18),
                        )),
                    Example1(),
                    Padding(
                        padding: EdgeInsets.symmetric(vertical: 15),
                        child: Text(
                          '示例2 构建选项并使用控制器',
                          style: TextStyle(fontSize: 18),
                        )),
                    Example2(),
                    Padding(
                        padding: EdgeInsets.symmetric(vertical: 15),
                        child: Text(
                          '示例3 自定义文本输入字段',
                          style: TextStyle(fontSize: 18),
                        )),
                    Example3(),
                    Padding(
                        padding: EdgeInsets.symmetric(vertical: 15),
                        child: Text(
                          '示例4 与示例2共享相同的存储',
                          style: TextStyle(fontSize: 18),
                        )),
                    Example4(),
                  ],
                ),
              ))),
        ));
  }
}

class Example1 extends StatefulWidget {
  const Example1({Key? key}) : super(key: key);

  [@override](/user/override)
  State<Example1> createState() => Example1State();
}

class Example1State extends State<Example1> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return ElasticAutocomplete(
        optionsBuilder: (TextEditingValue textEditingValue) {
      if (textEditingValue.text == '') {
        return const Iterable<String>.empty();
      }
      const List<String> options = [
        "app",
        "bar",
        "car",
        "dot",
        "ear",
        "foo",
        "god",
        "hop",
        "ice",
        "jam"
      ];
      return options.where((String option) {
        return option.contains(textEditingValue.text);
      });
    }, fieldViewBuilder: (BuildContext context,
            TextEditingController textEditingController,
            FocusNode focusNode,
            void Function() onFieldSubmitted) {
      // 自行设计字段视图
      return TextFormField(
          autofocus: true,
          // 必须在textFormField中设置controller, focusNode, 和onFieldSubmitted
          controller: textEditingController,
          focusNode: focusNode,
          onFieldSubmitted: (String value) {
            onFieldSubmitted();
          },
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
          ));
    });
  }
}

class Example2 extends StatefulWidget {
  const Example2({Key? key}) : super(key: key);

  [@override](/user/override)
  State<Example2> createState() => Example2State();
}

class Example2State extends State<Example2> {
  final _formKey = GlobalKey<FormState>();
  late FocusNode _node;
  late ElasticAutocompleteController<String> _elasticAutocompleteCtrl;
  late TextEditingController _textEditingCtrl;

  [@override](/user/override)
  void initState() {
    _node = FocusNode();
    _textEditingCtrl = TextEditingController();
    _elasticAutocompleteCtrl =
        ElasticAutocompleteController(id: 'example2', caseSensitive: false);
    super.initState();
  }

  [@override](/user/override)
  void dispose() {
    _textEditingCtrl.dispose();
    _node.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElasticAutocomplete(
              controller: _elasticAutocompleteCtrl,
              // 使用由控制器生成的optionsBuilder
              optionsBuilder: _elasticAutocompleteCtrl.optionsBuilder,
              fieldViewBuilder: _elasticAutocompleteCtrl.fieldViewBuilder(
                  decoration: const InputDecoration(
                border: OutlineInputBorder(),
              )),
              // 使用textEditingController获取TextFormField中的值
              textEditingController: _textEditingCtrl,
              // 设置textEditingController时,同时设置focusNode
              focusNode: _node,
            ),
            const SizedBox(height: 20),
            Row(
              children: [
                ElevatedButton(
                  onPressed: () async {
                    if (_formKey.currentState?.validate() ?? false) {
                      String val = _textEditingCtrl.text;
                      _textEditingCtrl.clear();
                      await _elasticAutocompleteCtrl.store(val);

                      if (!mounted) return;
                      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                          content: Text('Append "$val" to the options')));
                    }
                  },
                  child:
                      const Text("发送", style: TextStyle(color: Colors.white)),
                ),
                const SizedBox(
                  width: 10,
                ),
                ElevatedButton(
                  onPressed: () {
                    _elasticAutocompleteCtrl.clear();
                  },
                  child: const Text("清除",
                      style: TextStyle(color: Colors.white)),
                ),
              ],
            )
          ],
        ));
  }
}

class Example3 extends StatelessWidget {
  const Example3({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    ElasticAutocompleteController ctrl = ElasticAutocompleteController(
        id: 'example3',
        initialOptions: ["apple", "banana", "cat", "dog", "elephant"],
        showTopKWhenInputEmpty: 3);
    return ElasticAutocomplete(
        controller: ctrl,
        optionsBuilder: ctrl.optionsBuilder,
        fieldViewBuilder: ctrl.fieldViewBuilder(
            cursorColor: Colors.green,
            style: const TextStyle(color: Colors.green),
            decoration: const InputDecoration(
                border: OutlineInputBorder(),
                suffixIcon: Icon(Icons.search),
                hintText: '提示文字')));
  }
}

class Example4 extends StatelessWidget {
  const Example4({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    ElasticAutocompleteController ctrl = ElasticAutocompleteController(
        // 使用与example2相同的id
        id: 'example2');
    return ElasticAutocomplete(
        controller: ctrl,
        optionsBuilder: ctrl.optionsBuilder,
        fieldViewBuilder: ctrl.fieldViewBuilder(
            decoration: const InputDecoration(border: OutlineInputBorder())));
  }
}

更多关于Flutter自动补全插件elastic_autocomplete的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自动补全插件elastic_autocomplete的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用elastic_autocomplete插件来实现自动补全功能的代码示例。这个插件通常用于搜索功能,当用户输入文本时,它会根据输入内容显示建议列表。

首先,确保你已经在pubspec.yaml文件中添加了elastic_autocomplete依赖:

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

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

接下来是一个简单的使用示例:

  1. 导入必要的包
import 'package:flutter/material.dart';
import 'package:elastic_autocomplete/elastic_autocomplete.dart';
  1. 定义主应用程序
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Elastic Autocomplete Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SearchScreen(),
    );
  }
}
  1. 创建搜索屏幕
class SearchScreen extends StatefulWidget {
  @override
  _SearchScreenState createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  final TextEditingController _controller = TextEditingController();
  List<String> _suggestions = [
    'Apple',
    'Banana',
    'Orange',
    'Grape',
    'Pineapple',
    'Strawberry',
    'Blueberry',
    // 添加更多建议项
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Elastic Autocomplete Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: 'Search...',
                suffixIcon: IconButton(
                  icon: Icon(Icons.clear),
                  onPressed: () {
                    _controller.clear();
                  },
                ),
              ),
              onChanged: (value) {
                // 当用户输入文本时触发
                setState(() {}); // 触发UI更新以显示新的建议列表
              },
            ),
            SizedBox(height: 16),
            Expanded(
              child: _buildSuggestionList(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSuggestionList() {
    final String query = _controller.text.toLowerCase();
    final List<String> filteredSuggestions = _suggestions
        .where((suggestion) =>
            suggestion.toLowerCase().contains(query))
        .toList();

    return ElasticAutocomplete(
      suggestions: filteredSuggestions,
      onSuggestionSelected: (String suggestion) {
        _controller.value = _controller.value.copyWith(
          text: suggestion,
          selection: TextSelection.fromPosition(
            TextPosition(
              affinity: TextAffinity.downstream,
              offset: suggestion.length,
            ),
          ),
          composing: TextRange.empty,
        );
      },
      builder: (context, suggestions) {
        return ListView.builder(
          itemCount: suggestions.length,
          itemBuilder: (context, index) {
            final String suggestion = suggestions[index];
            return ListTile(
              leading: Icon(Icons.search),
              title: Text(suggestion),
              onTap: () {
                // 当用户点击建议项时触发
                _controller.text = suggestion;
              },
            );
          },
        );
      },
    );
  }
}

在这个示例中,我们创建了一个简单的搜索屏幕,其中包含一个TextField用于用户输入,以及一个使用ElasticAutocomplete小部件显示的建议列表。当用户输入文本时,_buildSuggestionList函数会根据输入内容过滤建议列表,并更新UI。当用户选择一个建议时,该建议会被填充到TextField中。

注意:elastic_autocomplete的具体API和用法可能会随着版本的更新而有所变化,因此请参考最新的官方文档和示例代码以获取最准确的信息。

回到顶部