Flutter搜索列表插件searchable_listview的使用

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

Flutter搜索列表插件searchable_listview的使用

Searchable ListView 插件介绍

Searchable ListView 是一个Flutter插件,它提供了一种简单的方法来过滤列表。以下是该插件的主要特性:

  • 轻松过滤列表:可以方便地对ListView进行过滤。
  • 支持异步列表:能够处理来自异步回调的数据。
  • 扩展列表:支持带有可展开项的列表。
  • 排序功能:允许用户根据特定规则对列表项进行排序。
  • 分页和下拉刷新:支持分页加载更多数据以及通过下拉操作刷新列表。
  • 自定义滚动动画效果:为ListView添加了滑动动画效果。
  • 高度可定制化:提供了丰富的属性用于调整UI样式,如加载时显示的Widget、错误提示等。

要开始使用此插件,请在项目的pubspec.yaml文件中添加依赖项:

dependencies:
  searchable_listview: ^2.16.0

使用示例

下面是一个完整的Dart代码示例,演示了如何在Flutter应用程序中集成并使用Searchable ListView插件。

示例应用结构

我们将创建一个简单的Flutter应用程序,其中包含以下功能:

  • 搜索演员名单(Actor List)
  • 添加新演员
  • 使用分隔符、自动关闭键盘等功能

主程序入口 (main.dart)

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const Scaffold(
        body: SafeArea(
          child: ExampleApp(),
        ),
      ),
    );
  }
}

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

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  final List<Actor> actors = [
    Actor(age: 47, name: 'Leonardo', lastName: 'DiCaprio'),
    Actor(age: 58, name: 'Johnny', lastName: 'Depp'),
    // ... 更多演员信息
  ];

  final Map<String, List<Actor>> mapOfActors = {
    'test 1': [
      Actor(age: 47, name: 'Leonardo', lastName: 'DiCaprio'),
      // ... 更多演员信息
    ],
    'test 2': [
      Actor(age: 58, name: 'Johnny', lastName: 'Depp'),
      // ... 更多演员信息
    ]
  };

  final TextEditingController searchTextController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: Column(
        children: [
          const Text('Searchable list with divider'),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(15),
              child: simpleSearchWithSort(),
            ),
          ),
          Align(
            alignment: Alignment.center,
            child: ElevatedButton(
              onPressed: addActor,
              child: const Text('Add actor'),
            ),
          )
        ],
      ),
    );
  }

  void addActor() {
    actors.add(Actor(
      age: 10,
      lastName: 'Ali',
      name: 'ALi',
    ));
    setState(() {});
  }

  Widget simpleSearchWithSort() {
    return SearchableList<Actor>(
      lazyLoadingEnabled: false,
      sortPredicate: (a, b) => a.age.compareTo(b.age),
      itemBuilder: (item) {
        return ActorItem(actor: item);
      },
      initialList: List.generate(
        200,
        (index) => Actor(age: 47, name: 'Leonardo', lastName: 'DiCaprio'),
      ),
      inputDecoration: InputDecoration(
        labelText: "Search Actor",
        fillColor: Colors.white,
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Colors.blue,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
    );
  }

  Widget renderSimpleSearchableList() {
    return SearchableList<Actor>(
      seperatorBuilder: (context, index) {
        return const Divider();
      },
      textStyle: const TextStyle(fontSize: 25),
      itemBuilder: (item) {
        return ActorItem(actor: item);
      },
      errorWidget: const Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.error,
            color: Colors.red,
          ),
          SizedBox(
            height: 20,
          ),
          Text('Error while fetching actors')
        ],
      ),
      initialList: actors,
      filter: (p0) {
        return actors.where((element) => element.name.contains(p0)).toList();
      },
      emptyWidget: const EmptyView(),
      onRefresh: () async {},
      inputDecoration: InputDecoration(
        labelText: "Search Actor",
        fillColor: Colors.white,
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Colors.blue,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
      closeKeyboardWhenScrolling: true,
    );
  }

  Widget sliverListViewBuilder() {
    return SearchableList<Actor>.sliver(
      initialList: actors,
      inputDecoration: InputDecoration(
        labelText: "Search Actor",
        fillColor: Colors.white,
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Colors.blue,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
      filter: (query) {
        return actors.where((element) => element.name.contains(query)).toList();
      },
      itemBuilder: (Actor actorItem) {
        return ActorItem(actor: actorItem);
      },
      sortWidget: const Icon(Icons.sort),
      sortPredicate: (a, b) {
        return a.age.compareTo(b.age);
      },
    );
  }

  Widget renderAsynchSearchableListview() {
    return SearchableList<Actor>.async(
      itemBuilder: (Actor item) {
        return ActorItem(actor: item);
      },
      asyncListCallback: () async {
        await Future.delayed(const Duration(seconds: 5));
        return actors;
      },
      asyncListFilter: (query, list) {
        return actors
            .where((element) =>
                element.name.contains(query) ||
                element.lastName.contains(query))
            .toList();
      },
      seperatorBuilder: (context, index) {
        return const Divider();
      },
      textStyle: const TextStyle(fontSize: 25),
      emptyWidget: const EmptyView(),
      inputDecoration: InputDecoration(
        labelText: "Search Actor",
        fillColor: Colors.white,
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Colors.blue,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
    );
  }

  Widget expansionSearchableList() {
    return SearchableList<Actor>.expansion(
      expansionListData: mapOfActors,
      expansionTitleBuilder: (p0) {
        return Container(
          color: Colors.grey[300],
          width: MediaQuery.of(context).size.width * 0.8,
          height: 30,
          child: Center(
            child: Text(p0.toString()),
          ),
        );
      },
      filterExpansionData: (p0) {
        final filteredMap = {
          for (final entry in mapOfActors.entries)
            entry.key: (mapOfActors[entry.key] ?? [])
                .where((element) => element.name.contains(p0))
                .toList()
        };
        return filteredMap;
      },
      textStyle: const TextStyle(fontSize: 25),
      expansionListBuilder: (int index, Actor _actor) {
        return ActorItem(
          actor: _actor,
        );
      },
      hideEmptyExpansionItems: true,
      emptyWidget: const EmptyView(),
      inputDecoration: InputDecoration(
        labelText: "Search Actor",
        fillColor: Colors.white,
        focusedBorder: OutlineInputBorder(
          borderSide: const BorderSide(
            color: Colors.blue,
            width: 1.0,
          ),
          borderRadius: BorderRadius.circular(10.0),
        ),
      ),
    );
  }
}

class ActorItem extends StatelessWidget {
  final Actor actor;

  const ActorItem({
    Key? key,
    required this.actor,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Container(
        height: 60,
        decoration: BoxDecoration(
          color: Colors.grey[200],
          borderRadius: BorderRadius.circular(10),
        ),
        child: Row(
          children: [
            const SizedBox(
              width: 10,
            ),
            Icon(
              Icons.star,
              color: Colors.yellow[700],
            ),
            const SizedBox(
              width: 10,
            ),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(
                  'Firstname: ${actor.name}',
                  style: const TextStyle(
                    color: Colors.black,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  'Lastname: ${actor.lastName}',
                  style: const TextStyle(
                    color: Colors.black,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  'Age: ${actor.age}',
                  style: const TextStyle(
                    color: Colors.black,
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(
          Icons.error,
          color: Colors.red,
        ),
        Text('no actor is found with this name'),
      ],
    );
  }
}

class Actor {
  int age;
  String name;
  String lastName;

  Actor({
    required this.age,
    required this.name,
    required this.lastName,
  });
}

解释

这段代码展示了如何使用SearchableListView来构建一个具有搜索功能的演员列表,并且还包含了其他实用的功能,例如添加新的演员条目。此外,我们还实现了不同类型的构造函数(默认、异步、展开式和Sliver),以满足不同的应用场景需求。

希望这个详细的例子能帮助你更好地理解和使用searchable_listview插件!如果你有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter搜索列表插件searchable_listview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter搜索列表插件searchable_listview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用searchable_listview插件来实现搜索列表功能的示例代码。这个插件允许你在列表视图中添加搜索功能,使用户能够快速找到他们感兴趣的项目。

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

dependencies:
  flutter:
    sdk: flutter
  searchable_listview: ^0.0.4  # 请注意版本号,使用最新版本

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

接下来是完整的示例代码,展示如何使用searchable_listview

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  // 示例数据
  final List<String> items = [
    'Apple',
    'Banana',
    'Cherry',
    'Date',
    'Elderberry',
    'Fig',
    'Grape',
    'Honeydew',
    'Indian Fig',
    'Jackfruit',
    // 添加更多项目以展示搜索功能
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Searchable ListView Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: SearchableDropdownListView(
          items: items,
          onItemFound: (index, value) {
            // 用户点击项目时的回调
            print("Item found: $value at index $index");
            // 可以在这里执行如导航到详情页等操作
          },
          searchInputDecoration: InputDecoration(
            prefixIcon: Icon(Icons.search),
            labelText: 'Search...',
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(12.0),
            ),
          ),
          itemBuilder: (context, index, value) {
            return ListTile(
              title: Text(value),
            );
          },
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们创建了一个包含一些水果名称的列表items
  2. 使用SearchableDropdownListView小部件来显示这个列表并添加搜索功能。
  3. onItemFound回调在用户点击列表中的项目时被调用,你可以在这里执行一些操作,比如导航到详情页。
  4. searchInputDecoration允许你自定义搜索输入框的样式。
  5. itemBuilder定义了每个列表项的样式,这里我们简单地使用了ListTile

运行这个示例,你应该能看到一个包含搜索输入框的列表,输入搜索词时列表会实时过滤显示匹配的项目。

回到顶部