Flutter浮动搜索栏插件material_floating_search_bar_2的使用

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

Flutter浮动搜索栏插件material_floating_search_bar_2的使用

简介

material_floating_search_bar_2 是一个Flutter包,它实现了可扩展的浮动搜索栏(也称为持久搜索),类似于Google在其应用中广泛使用的搜索栏。这个包是基于原作者删除后的仓库继续开发的版本。

CircularFloatingSearchBarTransition ExpandingFloatingSearchBarTransition SlideFadeFloatingSearchBarTransition

点击这里查看完整示例代码。

安装

请参考 安装指南

使用方法

基本用法

FloatingSearchBar 放置在主内容上方,并允许其填充所有可用空间:

@override
Widget build(BuildContext context) {
  return Scaffold(
    resizeToAvoidBottomInset: false,
    body: Stack(
      fit: StackFit.expand,
      children: [
        buildMap(),
        buildBottomNavigationBar(),
        buildFloatingSearchBar(),
      ],
    ),
  );
}

Widget buildFloatingSearchBar() {
  final isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;

  return FloatingSearchBar(
    hint: 'Search...',
    scrollPadding: const EdgeInsets.only(top: 16, bottom: 56),
    transitionDuration: const Duration(milliseconds: 800),
    transitionCurve: Curves.easeInOut,
    physics: const BouncingScrollPhysics(),
    axisAlignment: isPortrait ? 0.0 : -1.0,
    openAxisAlignment: 0.0,
    width: isPortrait ? 600 : 500,
    debounceDelay: const Duration(milliseconds: 500),
    onQueryChanged: (query) {
      // Call your model, bloc, controller here.
    },
    transition: CircularFloatingSearchBarTransition(),
    actions: [
      FloatingSearchBarAction(
        showIfOpened: false,
        child: CircularButton(
          icon: const Icon(Icons.place),
          onPressed: () {},
        ),
      ),
      FloatingSearchBarAction.searchToClear(
        showIfClosed: false,
      ),
    ],
    builder: (context, transition) {
      return ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: Material(
          color: Colors.white,
          elevation: 4.0,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: Colors.accents.map((color) {
              return Container(height: 112, color: color);
            }).toList(),
          ),
        ),
      );
    },
  );
}

与滚动组件一起使用

默认情况下,builder 返回的 Widget 不允许有无限高度。如果需要使用滚动组件,应设置 shrinkWraptruephysicsNeverScrollableScrollPhysics。也可以通过设置 isScrollControlledtrue 来允许无限高度,但需要注意搜索栏可能无法检测到背景区域的点击事件。

自定义选项

FloatingSearchBar 提供了多种自定义选项,包括但不限于:

字段 描述
body 显示在 FloatingSearchBar 下方的 widget。
accentColor 用于进度指示器等元素的颜色。
backgroundColor 卡片的背景颜色。
shadowColor 阴影颜色。
iconColor 图标颜色。
backdropColor 搜索栏打开时填充可用空间的颜色。
margins 边缘内边距。
padding 卡片的内边距。
insets leadingActions、输入字段和 actions 之间的内边距。
height 卡片的高度。
elevation 卡片的阴影高度。
width 搜索栏的宽度。
openWidth 打开时的宽度。
axisAlignment 对齐方式。
openAxisAlignment 打开时的对齐方式。
border 卡片的边框。
borderRadius 卡片的圆角。
hintStyle 输入提示文本样式。
queryStyle 输入文本样式。
clearQueryOnClose 关闭时是否清除查询。
automaticallyImplyDrawerHamburger 是否显示汉堡菜单。
closeOnBackdropTap 点击背景时是否关闭。
automaticallyImplyBackButton 是否自动显示返回按钮。
progress 进度条的状态。
transitionDuration 动画持续时间。
transitionCurve 动画曲线。
debounceDelay 输入延迟。
title 关闭时显示的标题。
hint 输入提示文本。
actions 输入字段右侧的操作按钮。
leadingActions 输入字段左侧的操作按钮。
onQueryChanged 查询变化时的回调。
onSubmitted 提交查询时的回调。
onFocusChanged 聚焦变化时的回调。
transition 动画过渡效果。
builder 搜索栏展开时的内容构建器。
controller 控制器,用于控制搜索栏的显示和隐藏。
isScrollControlled 是否使用自己的滚动控制器。
initiallyHidden 初始是否隐藏。

动画过渡

目前支持三种动画过渡效果:

过渡效果 描述
CircularFloatingSearchBarTransition 圆形展开。
ExpandingFloatingSearchBarTransition 全屏展开。
SlideFadeFloatingSearchBarTransition 滑动淡入淡出。

滚动监听

可以通过 FloatingSearchBarScrollNotifier 包装滚动组件来实现搜索栏随滚动消失和出现的效果:

class MyAwesomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FloatingSearchBarScrollNotifier(
      child: ListView.builder(
        itemCount: 42,
        itemBuilder: (_, index) => Item('Item $index'),
      ),
    );
  }
}

控制器

FloatingSearchBarController 可以用于控制 FloatingSearchBar 的展开、关闭、显示和隐藏等操作:

方法 描述
open() 展开搜索栏。
close() 关闭搜索栏。
show() 显示搜索栏。
hide() 隐藏搜索栏。
query 设置查询内容。
clear() 清除查询内容。

示例代码

以下是一个完整的示例代码,展示了如何使用 material_floating_search_bar_2 包:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material Floating Search Bar Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.light().copyWith(
        iconTheme: const IconThemeData(
          color: Color(0xFF4d4d4d),
        ),
        floatingActionButtonTheme: const FloatingActionButtonThemeData(
          elevation: 4,
        ),
      ),
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final FloatingSearchBarController controller = FloatingSearchBarController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      drawer: Drawer(
        child: Container(
          width: 200,
        ),
      ),
      body: buildSearchBar(),
    );
  }

  Widget buildSearchBar() {
    final List<FloatingSearchBarAction> actions = [
      FloatingSearchBarAction(
        child: CircularButton(
          icon: const Icon(Icons.place),
          onPressed: () {},
        ),
      ),
      FloatingSearchBarAction.searchToClear(
        showIfClosed: false,
      ),
    ];

    final bool isPortrait =
        MediaQuery.of(context).orientation == Orientation.portrait;

    return FloatingSearchBar(
      automaticallyImplyBackButton: false,
      controller: controller,
      hint: 'Search...',
      iconColor: Colors.grey,
      transitionDuration: const Duration(milliseconds: 800),
      transitionCurve: Curves.easeInOutCubic,
      physics: const BouncingScrollPhysics(),
      axisAlignment: isPortrait ? 0.0 : -1.0,
      openAxisAlignment: 0.0,
      actions: actions,
      progress: null,
      debounceDelay: const Duration(milliseconds: 500),
      onQueryChanged: (query) {
        // Handle query changes
      },
      onKeyEvent: (KeyEvent keyEvent) {
        if (keyEvent.logicalKey == LogicalKeyboardKey.escape) {
          controller.query = '';
          controller.close();
        }
      },
      scrollPadding: EdgeInsets.zero,
      transition: CircularFloatingSearchBarTransition(spacing: 16),
      builder: (BuildContext context, _) => buildExpandableBody(),
      body: buildBody(),
    );
  }

  Widget buildBody() {
    return Column(
      children: [
        Expanded(
          child: IndexedStack(
            index: 0,
            children: [
              Map(),
              SomeScrollableContent(),
            ],
          ),
        ),
        buildBottomNavigationBar(),
      ],
    );
  }

  Widget buildExpandableBody() {
    return Container(
      padding: const EdgeInsets.symmetric(vertical: 16),
      child: Material(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        clipBehavior: Clip.antiAlias,
        child: ListView.builder(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemCount: 10,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text('Item $index'),
            );
          },
        ),
      ),
    );
  }

  Widget buildBottomNavigationBar() {
    return BottomNavigationBar(
      onTap: (int value) {},
      currentIndex: 0,
      elevation: 16,
      type: BottomNavigationBarType.fixed,
      showUnselectedLabels: true,
      backgroundColor: Colors.white,
      selectedItemColor: Colors.blue,
      selectedFontSize: 11.5,
      unselectedFontSize: 11.5,
      unselectedItemColor: const Color(0xFF4d4d4d),
      items: const [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: 'Explore',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.search),
          label: 'Search',
        ),
      ],
    );
  }

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

class Map extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Image.asset(
      'assets/map.jpg',
      fit: BoxFit.cover,
    );
  }
}

class SomeScrollableContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FloatingSearchBarScrollNotifier(
      child: ListView.separated(
        padding: const EdgeInsets.only(top: kToolbarHeight),
        itemCount: 100,
        separatorBuilder: (BuildContext context, int index) => const Divider(),
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            title: Text('Item $index'),
          );
        },
      ),
    );
  }
}

以上代码展示了如何创建一个带有浮动搜索栏的应用程序,并展示了如何使用各种自定义选项和功能。希望这些信息能帮助你更好地理解和使用 material_floating_search_bar_2 包。


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

1 回复

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


当然,以下是如何在Flutter项目中使用material_floating_search_bar_2插件的详细代码示例。这个插件提供了一个浮动搜索栏,可以提升用户搜索体验。

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  material_floating_search_bar_2: ^0.10.0  # 请检查最新版本号

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

2. 导入包

在你的Dart文件中导入包:

import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart';

3. 使用浮动搜索栏

以下是一个完整的示例,展示如何在一个简单的Flutter应用中集成和使用浮动搜索栏:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final List<String> items = List.generate(100, (index) => "Item $index");
  late FloatingSearchBarController _controller;

  @override
  void initState() {
    super.initState();
    _controller = FloatingSearchBarController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Floating Search Bar Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Expanded(
              child: FloatingSearchBar(
                controller: _controller,
                suggestions: items,
                onQueryChanged: (query) {
                  // 处理搜索查询变化
                  setState(() {});
                },
                onSelected: (item) {
                  // 处理选中的项目
                  print("Selected: $item");
                },
                transitionDuration: const Duration(milliseconds: 300),
                transitionCurve: Curves.easeInOut,
                openAxisAlignment: 0.0,
                axisAlignment: 0.0,
                searchBarStyle: FloatingSearchBarStyle(
                  margin: const EdgeInsets.all(8),
                  containerDecoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(16),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey.withOpacity(0.2),
                        spreadRadius: 5,
                        blurRadius: 7,
                        offset: Offset(0, 3),
                      ),
                    ],
                  ),
                  textStyle: TextStyle(fontSize: 18),
                  hintTextStyle: TextStyle(fontSize: 18, color: Colors.grey),
                ),
                leadingActions: [
                  FloatingSearchBarAction(
                    icon: Icons.clear,
                    onPressed: () {
                      _controller.clear();
                    },
                  ),
                ],
                trailingActions: [
                  FloatingSearchBarAction.searchToClear(
                    showIfOpened: true,
                  ),
                ],
              ),
            ),
            Expanded(
              child: AnimatedList(
                itemBuilder: (context, index, animation) {
                  return SlideTransition(
                    position: animation.drive(Tween<Offset>(
                      begin: Offset(0, 1),
                      end: Offset.zero,
                    )),
                    child: ListTile(
                      title: Text(items[index]),
                    ),
                  );
                },
                initialItemCount: items.length,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

4. 解释代码

  • 依赖添加和导入:在pubspec.yaml中添加依赖,并在Dart文件中导入。
  • 创建控制器:在HomeScreenState中创建一个FloatingSearchBarController实例。
  • 构建搜索栏:使用FloatingSearchBar小部件来创建浮动搜索栏,并设置其属性,如controllersuggestionsonQueryChangedonSelected等。
  • 处理搜索结果:在onQueryChangedonSelected回调中处理搜索查询和选中的项目。
  • 显示结果:使用AnimatedList来动态显示搜索结果。

这个示例展示了如何在一个简单的Flutter应用中集成material_floating_search_bar_2插件,并提供了一个基本的搜索功能。你可以根据需要进行进一步的定制和扩展。

回到顶部