Android Flutter实现搜索的三种方式详解

作者:大前端之旅 时间:2023-07-10 18:00:49 

示例 1 :使用搜索表单创建全屏模式

我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮。按下此按钮时,将出现一个全屏模式对话框。它不会突然跳出来,而是带有淡入淡出动画和幻灯片动画(从上到下)。在圆形搜索字段旁边,有一个取消按钮,可用于关闭模式。在搜索字段下方,我们会显示一些搜索历史记录(您可以添加其他内容,如建议、类别等)。

编码

我们通过定义一个扩展 ModalRoute 类的名为FullScreenSearchModal的类来创建完整模式。

main.dart中的完整源代码及说明:

// 大前端之旅
// main.dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     // remove the debug banner
     debugShowCheckedModeBanner: false,
     title: '大前端之旅',
     theme: ThemeData(
       primarySwatch: Colors.green,
     ),
     home: const KindaCodeDemo(),
   );
 }
}

// this class defines the full-screen search modal
// by extending the ModalRoute class
class FullScreenSearchModal extends ModalRoute {
 @override
 Duration get transitionDuration => const Duration(milliseconds: 500);

 @override
 bool get opaque => false;

 @override
 bool get barrierDismissible => false;

 @override
 Color get barrierColor => Colors.black.withOpacity(0.6);

 @override
 String? get barrierLabel => null;

 @override
 bool get maintainState => true;

 @override
 Widget buildPage(
   BuildContext context,
   Animation<double> animation,
   Animation<double> secondaryAnimation,
 ) {
   return Scaffold(
     body: SafeArea(
       child: Padding(
         padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
         child: Column(
           mainAxisSize: MainAxisSize.min,
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             // implement the search field
             Row(
               mainAxisAlignment: MainAxisAlignment.spaceBetween,
               children: [
                 Expanded(
                   child: TextField(
                     autofocus: true,
                     decoration: InputDecoration(
                       contentPadding: const EdgeInsets.symmetric(
                           vertical: 0, horizontal: 20),
                       filled: true,
                       fillColor: Colors.grey.shade300,
                       suffixIcon: const Icon(Icons.close),
                       hintText: 'Search 大前端之旅',
                       border: OutlineInputBorder(
                           borderSide: BorderSide.none,
                           borderRadius: BorderRadius.circular(30)),
                     ),
                   ),
                 ),
                 const SizedBox(
                   width: 10,
                 ),
                 // This button is used to close the search modal
                 TextButton(
                     onPressed: () => Navigator.of(context).pop(),
                     child: const Text('Cancel'))
               ],
             ),

             // display other things like search history, suggestions, search results, etc.
             const SizedBox(
               height: 20,
             ),
             const Padding(
               padding: EdgeInsets.only(left: 5),
               child: Text('Recently Searched',
                   style:
                       TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
             ),
             const ListTile(
               title: Text('Flutter tutorials'),
               leading: Icon(Icons.search),
               trailing: Icon(Icons.close),
             ),
             const ListTile(
               title: Text('How to fry a chicken'),
               leading: Icon(Icons.search),
               trailing: Icon(Icons.close),
             ),
             const ListTile(
               title: Text('大前端之旅'),
               leading: Icon(Icons.search),
               trailing: Icon(Icons.close),
             ),
             const ListTile(
               title: Text('Goodbye World'),
               leading: Icon(Icons.search),
               trailing: Icon(Icons.close),
             ),
             const ListTile(
               title: Text('Cute Puppies'),
               leading: Icon(Icons.search),
               trailing: Icon(Icons.close),
             )
           ],
         ),
       ),
     ),
   );
 }

 // animations for the search modal
 @override
 Widget buildTransitions(BuildContext context, Animation<double> animation,
     Animation<double> secondaryAnimation, Widget child) {
   // add fade animation
   return FadeTransition(
     opacity: animation,
     // add slide animation
     child: SlideTransition(
       position: Tween<Offset>(
         begin: const Offset(0, -1),
         end: Offset.zero,
       ).animate(animation),
       child: child,
     ),
   );
 }
}

// This is the main screen of the application
class KindaCodeDemo extends StatelessWidget {
 const KindaCodeDemo({Key? key}) : super(key: key);

 void _showModal(BuildContext context) {
   Navigator.of(context).push(FullScreenSearchModal());
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(title: const Text('大前端之旅'), actions: [
       // this button is used to open the search modal
       IconButton(
         icon: const Icon(Icons.search),
         onPressed: () => _showModal(context),
       )
     ]),
     body: Container(),
   );
 }
}

示例 2:AppBar 内的搜索字段(最常见于娱乐应用程序)

通常,许多娱乐应用程序(包括 Facebook、Youtube、Spotify 等大型应用程序)默认不显示搜索字段,而是显示搜索图标按钮。按下此按钮时,将显示搜索字段。

我们要制作的演示应用程序包含 2 个屏幕(页面):HomePageSearchPage。用户可以通过点击搜索图标按钮从主页移动到搜索页面。搜索字段将通过使用SearchPage 的 AppBar的title参数来实现。

让我们看看它是如何工作的:

编码

./lib/main.dart中的完整源代码及说明:

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

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

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

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
       // Remove the debug banner
       debugShowCheckedModeBanner: false,
       title: '大前端之旅',
       theme: ThemeData(
         primarySwatch: Colors.indigo,
       ),
       home: const HomePage());
 }
}

// Home Page
class HomePage extends StatelessWidget {
 const HomePage({Key? key}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: const Text('大前端之旅'),
       actions: [
         // Navigate to the Search Screen
         IconButton(
             onPressed: () => Navigator.of(context)
                 .push(MaterialPageRoute(builder: (_) => const SearchPage())),
             icon: const Icon(Icons.search))
       ],
     ),
   );
 }
}

// Search Page
class SearchPage extends StatelessWidget {
 const SearchPage({Key? key}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
         // The search area here
         title: Container(
       width: double.infinity,
       height: 40,
       decoration: BoxDecoration(
           color: Colors.white, borderRadius: BorderRadius.circular(5)),
       child: Center(
         child: TextField(
           decoration: InputDecoration(
               prefixIcon: const Icon(Icons.search),
               suffixIcon: IconButton(
                 icon: const Icon(Icons.clear),
                 onPressed: () {
                   /* Clear the search field */
                 },
               ),
               hintText: 'Search...',
               border: InputBorder.none),
         ),
       ),
     )),
   );
 }
}

示例 3:搜索字段和 SliverAppBar

广告搜索是许多电子商务应用程序最重要的功能之一,因此它们通常以最容易识别的方式显示搜索字段,并且从一开始就占用大量空间(亚马逊、Shopee 等)。

编码

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

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

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

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
       // Remove the debug banner
       debugShowCheckedModeBanner: false,
       title: '大前端之旅',
       theme: ThemeData(
         primarySwatch: Colors.deepPurple,
       ),
       home: const HomePage());
 }
}

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

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

class _HomePageState extends State<HomePage> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     body: CustomScrollView(
       slivers: [
         SliverAppBar(
           floating: true,
           pinned: true,
           snap: false,
           centerTitle: false,
           title: const Text('大前端之旅'),
           actions: [
             IconButton(
               icon: const Icon(Icons.shopping_cart),
               onPressed: () {},
             ),
           ],
           bottom: AppBar(
             title: Container(
               width: double.infinity,
               height: 40,
               color: Colors.white,
               child: const Center(
                 child: TextField(
                   decoration: InputDecoration(
                       hintText: 'Search for something',
                       prefixIcon: Icon(Icons.search),
                       suffixIcon: Icon(Icons.camera_alt)),
                 ),
               ),
             ),
           ),
         ),
         // Other Sliver Widgets
         SliverList(
           delegate: SliverChildListDelegate([
             const SizedBox(
               height: 400,
               child: Center(
                 child: Text(
                   'This is an awesome shopping platform',
                 ),
               ),
             ),
             Container(
               height: 1000,
               color: Colors.pink,
             ),
           ]),
         ),
       ],
     ),
   );
 }
}

结论

您已经研究了在 Flutter 中实现全屏搜索框的端到端示例。这种搜索方式如今非常流行,您可以在许多大型应用程序和移动网站中注意到它。

来源:https://juejin.cn/post/7129292610295824421

标签:Android,Flutter,搜索
0
投稿

猜你喜欢

  • 详解Spring Security如何在权限中使用通配符

    2023-04-17 23:41:54
  • Java线程池实现原理总结

    2023-04-15 02:37:11
  • 如何使用Java调用Linux系统命令

    2021-12-24 20:45:31
  • .net 随机生成汉字

    2022-01-22 08:33:33
  • 以Java代码为例讲解设计模式中的简单工厂模式

    2023-02-09 15:14:17
  • SpringBoot项目中的多数据源支持的方法

    2022-01-12 03:42:19
  • 详谈.net中的垃圾回收机制

    2022-12-04 03:52:27
  • springboot读取自定义配置文件时出现乱码解决方案

    2022-01-29 11:09:40
  • java将一个目录下的所有文件复制n次

    2023-03-04 00:13:12
  • 用Java实现简单计算器功能

    2023-03-29 17:44:16
  • Android Build Variants 为项目设置变种版本的方法

    2023-04-26 10:29:07
  • Base64编码解码原理及C#编程实例

    2022-05-07 03:58:53
  • SpringBoot 多Profile使用与切换方式

    2022-04-13 14:58:27
  • Android数据库中事务操作方法之银行转账示例

    2023-07-22 07:56:13
  • MyBatis配置的应用与对比jdbc的优势

    2023-08-27 07:03:47
  • 关于maven使用过程中无法导入依赖的一些总结

    2021-12-16 01:51:20
  • Java客户端调用.NET的WebService实例

    2023-11-03 17:22:00
  • WindowsForm实现警告消息框的实例代码

    2023-05-25 00:00:54
  • Android进程运行中权限被收回导致关闭的问题解决

    2023-11-21 16:56:45
  • C#泛型方法在lua中表示的一种设计详解

    2022-08-24 20:03:12
  • asp之家 软件编程 m.aspxhome.com