Flutter动态搜索下拉选择插件dynamic_searchable_drop_down的使用

Flutter 动态搜索下拉选择插件 dynamic_searchable_drop_down 的使用

简介

Flutter 简单且健壮的下拉搜索插件,具有项目搜索功能,可以使用离线项目列表或过滤 URL 进行轻松定制。

Dropdown search

关键特性

  • 同步和/或异步项目(在线、离线、数据库等)
  • 可搜索的下拉框
  • 三种下拉模式:菜单/底部表单/模态底部表单/对话框
  • 单选和多选
  • 材料设计下拉框
  • 易于自定义的用户界面
  • 处理浅色和深色主题
  • 轻松实现到无状态小部件
  • 支持多级项目
Dropdown search Dropdown search
Dropdown search Dropdown search

packages.yaml

dropdown_search: <latest version>

导入

import 'package:dropdown_search/dropdown_search.dart';

简单实现

DropdownSearch<String>(
    popupProps: PopupProps.menu(
        showSelectedItems: true,
        disabledItemFn: (String s) => s.startsWith('I'),
    ),
    items: ["Brazil", "Italia (Disabled)", "Tunisia", 'Canada'],
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(
            labelText: "Menu mode",
            hintText: "country in menu mode",
        ),
    ),
    onChanged: print,
    selectedItem: "Brazil",
)

DropdownSearch<String>.multiSelection(
    items: ["Brazil", "Italia (Disabled)", "Tunisia", 'Canada'],
    popupProps: PopupPropsMultiSelection.menu(
        showSelectedItems: true,
        disabledItemFn: (String s) => s.startsWith('I'),
    ),
    onChanged: print,
    selectedItems: ["Brazil"],
)

自定义显示字段 (itemAsString)

DropdownSearch<UserModel>(
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringByName(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "User by name"),
    ),
)

DropdownSearch<UserModel>(
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringById(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "User by id"),
    ),
)

自定义筛选函数

DropdownSearch<UserModel>(
    filterFn: (user, filter) =>
    user.userFilterByCreationDate(filter),
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringByName(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    ),
)

自定义搜索模式

DropdownSearch<UserModel>(
    popupProps: PopupProps.bottomSheet(),
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsString(),
    onChanged: (UserModel? data) => print(data),
)

验证

DropdownSearch(
    items: ["Brazil", "France", "Tunisia", "Canada"],
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    onChanged: print,
    selectedItem: "Tunisia",
    validator: (String? item) {
    if (item == null)
      return "Required field";
    else if (item == "Brazil")
      return "Invalid item";
    else
      return null;
    },
)

使用 Dio 包进行端点实现

DropdownSearch<UserModel>(
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    asyncItems: (String filter) async {
        var response = await Dio().get(
            "http://5d85ccfb1e61af001471bf60.mockapi.io/user",
            queryParameters: {"filter": filter},
        );
        var models = UserModel.fromJsonList(response.data);
        return models;
    },
    onChanged: (UserModel? data) {
      print(data);
    },
)

布局自定义

你可以自定义 DropdownSearch 及其项目的布局。 https://github.com/salim-lachdhaf/searchable_dropdown/tree/master/example#custom-layout-endpoint-example

完整文档 https://pub.dev/documentation/dropdown_search/latest/dropdown_search/DropdownSearch-class.html

注意事项

要使用模板作为项目类型,并且不想使用自定义函数 itemAsStringcompareFn,则需要实现 toStringequalshashCode,如下所示:

class UserModel {
  final String id;
  final DateTime createdAt;
  final String name;
  final String avatar;

  UserModel({this.id, this.createdAt, this.name, this.avatar});

  factory UserModel.fromJson(Map<String, dynamic> json) {
    if (json == null) return null;
    return UserModel(
      id: json["id"],
      createdAt:
          json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]),
      name: json["name"],
      avatar: json["avatar"],
    );
  }

  static List<UserModel> fromJsonList(List list) {
    if (list == null) return null;
    return list.map((item) => UserModel.fromJson(item)).toList();
  }

  ///此方法将防止覆盖 toString
  String userAsString() {
    return '#${this.id} ${this.name}';
  }

  ///此方法将防止覆盖 toString
  bool userFilterByCreationDate(String filter) {
    return this.createdAt.toString().contains(filter);
  }

  ///自定义比较函数以检查两个用户是否相等
  bool isEqual(UserModel model) {
    return this.id == model.id;
  }

  [@override](/user/override)
  String toString() => name;
}

查看更多示例

https://github.com/salim-lachdhaf/searchable_dropdown/tree/master/example

支持

如果该插件对你有用,帮助你交付应用,节省了大量时间,或者你想支持该项目,我很感激你能买杯咖啡支持我。

Buy Me A Coffee

许可证

MIT


完整示例代码

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      themeMode: ThemeMode.dark,
      darkTheme: ThemeData(brightness: Brightness.light),
      debugShowCheckedModeBanner: false,
      title: 'DropDown Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Searchable Drop Down'),
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(10),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              const SizedBox(
                height: 50,
              ),
              SearchableDropdown(
                disabledColor: Colors.blue,
                hint: '-Select-',
                outlineColor: Colors.black,
                dropDownList: const [
                  'India',
                  'America',
                  'United Kingdom',
                  'Norway'
                ],
                onSelected: (val) {
                  debugPrint('value is $val');
                },
              ),
              const SizedBox(
                height: 50,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter动态搜索下拉选择插件dynamic_searchable_drop_down的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动态搜索下拉选择插件dynamic_searchable_drop_down的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


dynamic_searchable_drop_down 是一个 Flutter 插件,它提供了一个可搜索的下拉选择框。用户可以输入文本进行过滤,并从下拉列表中选择一个选项。这个插件非常适合需要在大量选项中进行选择的场景。

安装插件

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

dependencies:
  flutter:
    sdk: flutter
  dynamic_searchable_drop_down: ^1.0.0 # 请使用最新版本

然后运行 flutter pub get 来安装插件。

使用示例

下面是一个简单的使用示例,展示了如何在 Flutter 应用中使用 dynamic_searchable_drop_down 插件。

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dynamic Searchable Dropdown Example'),
        ),
        body: Center(
          child: SearchableDropdownExample(),
        ),
      ),
    );
  }
}

class SearchableDropdownExample extends StatefulWidget {
  [@override](/user/override)
  _SearchableDropdownExampleState createState() => _SearchableDropdownExampleState();
}

class _SearchableDropdownExampleState extends State<SearchableDropdownExample> {
  List<String> items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig', 'Grape'];
  String selectedItem;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: DynamicSearchableDropdown<String>(
        items: items,
        hint: 'Select an item',
        onChanged: (value) {
          setState(() {
            selectedItem = value;
          });
        },
        selectedItem: selectedItem,
      ),
    );
  }
}

参数说明

  • items: 一个包含所有可选项的列表。
  • hint: 在没有选择任何项时显示的提示文本。
  • onChanged: 当用户选择一个项时调用的回调函数。
  • selectedItem: 当前选中的项。

自定义样式

你可以通过传递额外的参数来自定义下拉框的样式,例如:

DynamicSearchableDropdown<String>(
  items: items,
  hint: 'Select an item',
  onChanged: (value) {
    setState(() {
      selectedItem = value;
    });
  },
  selectedItem: selectedItem,
  decoration: InputDecoration(
    border: OutlineInputBorder(),
    labelText: 'Fruits',
  ),
  itemBuilder: (context, item) {
    return ListTile(
      title: Text(item),
    );
  },
);

处理复杂对象

如果你需要处理复杂对象而不仅仅是字符串,你可以使用 valuedisplayValue 来分别表示对象的实际值和显示值:

class Fruit {
  final String name;
  final String color;

  Fruit(this.name, this.color);
}

class SearchableDropdownExample extends StatefulWidget {
  [@override](/user/override)
  _SearchableDropdownExampleState createState() => _SearchableDropdownExampleState();
}

class _SearchableDropdownExampleState extends State<SearchableDropdownExample> {
  List<Fruit> items = [
    Fruit('Apple', 'Red'),
    Fruit('Banana', 'Yellow'),
    Fruit('Cherry', 'Red'),
    Fruit('Date', 'Brown'),
    Fruit('Elderberry', 'Purple'),
    Fruit('Fig', 'Purple'),
    Fruit('Grape', 'Green'),
  ];
  Fruit selectedItem;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: DynamicSearchableDropdown<Fruit>(
        items: items,
        hint: 'Select a fruit',
        onChanged: (value) {
          setState(() {
            selectedItem = value;
          });
        },
        selectedItem: selectedItem,
        value: (item) => item,
        displayValue: (item) => item.name,
      ),
    );
  }
}
回到顶部