返回顶部
首页 > 资讯 > 移动开发 >Flutter实现自定义搜索框AppBar的示例代码
  • 430
分享到

Flutter实现自定义搜索框AppBar的示例代码

2024-04-02 19:04:59 430人浏览 八月长安
摘要

目录介绍效果图实现步骤完整源码总结介绍 开发中,页面头部为搜索样式的设计非常常见,为了可以像系统AppBar那样使用,这篇文章记录下在Flutter中自定义一个通用的搜索框AppBa

介绍

开发中,页面头部为搜索样式的设计非常常见,为了可以像系统AppBar那样使用,这篇文章记录下在Flutter中自定义一个通用的搜索框AppBar记录。

功能点: 搜索框、返回键、清除搜索内容功能、键盘处理。

效果图

实现步骤

首先我们先来看下AppBar的源码,实现了PreferredSizeWidget类,我们可以知道这个类主要是控制AppBar的高度的,Scaffold脚手架里的AppBar的参数类型就是PreferredSizeWidget类型。

class AppBar extends StatefulWidget implements PreferredSizeWidget{
...
preferredSize = _PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height),
...

/// {@template flutter.material.appbar.toolbarHeight}
/// Defines the height of the toolbar component of an [AppBar].
///
/// By default, the value of `toolbarHeight` is [kToolbarHeight].
/// {@endtemplate}
final double? toolbarHeight;

...
/// The height of the toolbar component of the [AppBar].
const double kToolbarHeight = 56.0;

}

abstract class PreferredSizeWidget implements Widget {
  // 设置在不受约束下希望的大小
  // 设置高度:Size.fromHeight(myAppBarHeight)
  Size get preferredSize;
}

为了方便扩展,可以在Scaffold里使用,我们需要创建AppBarSearch类继承有状态StatefulWidget类并实现PreferredSizeWidget类,实现preferredSize方法,并设置高度。

class AppBarSearch extends StatefulWidget implements PreferredSizeWidget {

@override
Size get preferredSize => Size.fromHeight(height);

}

因为ScaffoldAppBar实现了状态栏的适配,核心见下方源码:

//获取状态栏高度
MediaQuery.of(context).padding.top;

这里我们直接返回AppBar,并进行改造。(当然这里也可以不返回AppBar我们自己处理状态栏的高度也行)。

思路: AppBar title字段自定义输入框,主要通过文本框监听实现清除搜索内容和显示清除按钮的功能,通过输入框是否有焦点监听进行刷新布局,通过定义回调函数的方式来进行搜索内容的监听。

// 输入框控制
_controller = widget.controller ?? TextEditinGController();
// 焦点控制
_focusnode = widget.focusNode ?? FocusNode();
// 焦点获取失去监听
_focusNode?.addListener(() => setState(() {}));
// 文本输入监听
_controller?.addListener(() => setState(() {}));

键盘搜素监听:

只需设置TextField的这两个属性即可。

textInputAction: TextInputAction.search,
onSubmitted: widget.onSearch, //输入框完成触发

键盘弹出收起处理:

iOS中键盘的处理是需要我们自己来进行处理的,我们需要的功能是点击搜索框之外的地方失去焦点从而关闭键盘,这里我使用了处理键盘的一个插件flutter_keyboard_visibility: ^5.1.0,在我们需要处理焦点事件页面根布局使用KeyboardDismissOnTap外部包裹即可,这个插件还可以主动控制键盘的弹出和收起,有兴趣的小伙伴可以了解下。

return KeyboardDismissOnTap(
    child: Material();

完整源码

/// 搜索AppBar
class AppBarSearch extends StatefulWidget implements PreferredSizeWidget {
  AppBarSearch({
    Key? key,
    this.borderRadius = 10,
    this.autoFocus = false,
    this.focusNode,
    this.controller,
    this.height = 40,
    this.value,
    this.leading,
    this.backgroundColor,
    this.suffix,
    this.actions = const [],
    this.hintText,
    this.onTap,
    this.onClear,
    this.onCancel,
    this.onChanged,
    this.onSearch,
    this.onRightTap,
  }) : super(key: key);
  final double? borderRadius;
  final bool? autoFocus;
  final FocusNode? focusNode;
  final TextEditingController? controller;

  // 输入框高度 默认40
  final double height;

  // 默认值
  final String? value;

  // 最前面的组件
  final Widget? leading;

  // 背景色
  final Color? backgroundColor;

  // 搜索框内部后缀组件
  final Widget? suffix;

  // 搜索框右侧组件
  final List<Widget> actions;

  // 输入框提示文字
  final String? hintText;

  // 输入框点击回调
  final VoidCallback? onTap;

  // 清除输入框内容回调
  final VoidCallback? onClear;

  // 清除输入框内容并取消输入
  final VoidCallback? onCancel;

  // 输入框内容改变
  final ValueChanged<String>? onChanged;

  // 点击键盘搜索
  final ValueChanged<String>? onSearch;

  // 点击右边widget
  final VoidCallback? onRightTap;

  @override
  _AppBarSearchState createState() => _AppBarSearchState();

  @override
  Size get preferredSize => Size.fromHeight(height);
}

class _AppBarSearchState extends State<AppBarSearch> {
  TextEditingController? _controller;
  FocusNode? _focusNode;

  bool get isFocus => _focusNode?.hasFocus ?? false; //是否获取焦点

  bool get isTextEmpty => _controller?.text.isEmpty ?? false; //输入框是否为空

  bool get isActionEmpty => widget.actions.isEmpty; // 右边布局是否为空

  bool isshowCancel = false;

  @override
  void initState() {
    _controller = widget.controller ?? TextEditingController();
    _focusNode = widget.focusNode ?? FocusNode();
    if (widget.value != null) _controller?.text = widget.value ?? "";
    // 焦点获取失去监听
    _focusNode?.addListener(() => setState(() {}));
    // 文本输入监听
    _controller?.addListener(() {
      setState(() {});
    });
    super.initState();
  }

  // 清除输入框内容
  void _onClearInput() {
    setState(() {
      _controller?.clear();
    });
    widget.onClear?.call();
  }

  // 取消输入框编辑失去焦点
  void _onCancelInput() {
    setState(() {
      _controller?.clear();
      _focusNode?.unfocus(); //失去焦点
    });
    // 执行onCancel
    widget.onCancel?.call();
  }

  Widget _suffix() {
    if (!isTextEmpty) {
      return InkWell(
        onTap: _onClearInput,
        child: SizedBox(
          width: widget.height,
          height: widget.height,
          child: Icon(Icons.cancel, size: 22, color: Color(0xFF999999)),
        ),
      );
    }
    return widget.suffix ?? SizedBox();
  }

  List<Widget> _actions() {
    List<Widget> list = [];
    if (isFocus || !isTextEmpty) {
      list.add(InkWell(
        onTap: widget.onRightTap ?? _onCancelInput,
        child: Container(
          constraints: BoxConstraints(minWidth: 48.w),
          alignment: Alignment.center,
          child: MyText(
            '搜索',
            fontColor: MyColors.color_666666,
            fontSize: 14.sp,
          ),
        ),
      ));
    } else if (!isActionEmpty) {
      list.addAll(widget.actions);
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    return AppBar(
      backgroundColor: widget.backgroundColor,
      //阴影z轴
      elevation: 0,
      // 标题与其他控件的间隔
      titleSpacing: 0,
      leadingWidth: 40.w,
      leading: widget.leading ??
          InkWell(
            child: Icon(
              Icons.arrow_back_ios_outlined,
              color: MyColors.color_666666,
              size: 16.w,
            ),
            onTap: () {
              Routes.finish(context);
            },
          ),
      title: Container(
          margin: EdgeInsetsDirectional.only(end: 10.w),
          height: widget.height,
          decoration: BoxDecoration(
            color: Color(0xFFF2F2F2),
            borderRadius: BorderRadius.circular(widget.borderRadius ?? 0),
          ),
          child: Container(
            child: Row(
              children: [
                SizedBox(
                  width: widget.height,
                  height: widget.height,
                  child:
                      Icon(Icons.search, size: 20.w, color: Color(0xFF999999)),
                ),
                Expanded(
                  // 权重
                  flex: 1,
                  child: TextField(
                    autofocus: widget.autoFocus ?? false,
                    // 是否自动获取焦点
                    focusNode: _focusNode,
                    // 焦点控制
                    controller: _controller,
                    // 与输入框交互控制器
                    //装饰
                    decoration: InputDecoration(
                      isDense: true,
                      border: InputBorder.none,
                      hintText: widget.hintText ?? '请输入关键字',
                      hintStyle: TextStyle(
                          fontSize: 14.sp, color: MyColors.color_666666),
                    ),
                    style: TextStyle(
                      fontSize: 14.sp,
                      color: MyColors.color_333333,
                    ),
                    // 键盘动作右下角图标
                    textInputAction: TextInputAction.search,
                    onTap: widget.onTap,
                    // 输入框内容改变回调
                    onChanged: widget.onChanged,
                    onSubmitted: widget.onSearch, //输入框完成触发
                  ),
                ),
                _suffix(),
              ],
            ),
          )),
      actions: _actions(),
    );
  }

  @override
  void dispose() {
    _controller?.dispose();
    _focusNode?.dispose();
    super.dispose();
  }
}

总结

整体设计思路还是非常简单的,主要就是通过两个监听来控制我们想要达到的交互效果,还有就是对dart中函数Funcation作为对象的加深理解,通过自定义搜索AppBar可以了解系统到AppBar的一些设计思路,这里主要还是记录下我个人在做这个组件过程中的一个思路,希望对大家有所帮助~

到此这篇关于Flutter实现自定义搜索框AppBar的示例代码的文章就介绍到这了,更多相关Flutter搜索框内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Flutter实现自定义搜索框AppBar的示例代码

本文链接: https://lsjlt.com/news/145883.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Flutter实现自定义搜索框AppBar的示例代码
    目录介绍效果图实现步骤完整源码总结介绍 开发中,页面头部为搜索样式的设计非常常见,为了可以像系统AppBar那样使用,这篇文章记录下在Flutter中自定义一个通用的搜索框AppBa...
    99+
    2024-04-02
  • Flutter怎么实现自定义搜索框AppBar
    这篇文章主要讲解了“Flutter怎么实现自定义搜索框AppBar”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Flutter怎么实现自定义搜索框AppBar”吧!介绍开发中,页面头部为搜索...
    99+
    2023-06-30
  • Flutter自定义Appbar搜索框效果
    本文实例为大家分享了Flutter自定义Appbar搜索框效果的具体代码,供大家参考,具体内容如下 首先看一下实现本次实现的效果。 本来想直接偷懒从flutter pub上找个能用...
    99+
    2024-04-02
  • Flutter实现自定义筛选框的示例代码
    目录一、首先自定义筛选框的按钮视图,布局很简单,一个listView就可以搞定。二、定义筛选数据展示列表视图。一、首先自定义筛选框的按钮视图,布局很简单,一个listView就可以搞...
    99+
    2024-04-02
  • Flutter自定义搜索框效果
    本文实例为大家分享了Flutter自定义搜索框效果的具体代码,供大家参考,具体内容如下 效果 实现方式 import 'package:dio/dio.dart'; impor...
    99+
    2024-04-02
  • Android实现自定义加载框的代码示例
    App在与服务器进行网络交互的时候,需要有一个提示的加载框,如图: 此时我们可以自定义一个加载中的对话框,代码如下: public class LoadingDialog...
    99+
    2022-06-06
    自定义 示例 Android
  • Flutter实现自定义下拉选择框的示例详解
    在一些列表页面中,我们经常会有上方筛选项的的需求,点击出现一个下拉菜单,多选、单选、列表选等,而在Flutter中,并没有现成的这样的组件,找第三方的扩展有时候又会受到一定限制,所以...
    99+
    2024-04-02
  • C/C++ QT实现自定义对话框的示例代码
    对话框分为多种,常见的有通用对话框,自定义对话框,模态对话框,非模态对话框等,其中通用对话框包括了,QFileDialog文件对话框,QColorDialog颜色对话框,QFontD...
    99+
    2024-04-02
  • Swift代码自定义UIView实现示例
    Swift自定义View和OC自定义View的原理都是一样的,重写init()方法或initWithFrame()方法,下面简单说说如何自定义swift UIView 主要是重写in...
    99+
    2024-04-02
  • Android实现自定义圆角对话框Dialog的示例代码
    前言: 项目中多处用到对话框,用系统对话框太难看,就自己写一个自定义对话框。   对话框包括:1、圆角       2、app图标 , 提示文本,关闭对话框的"确定"...
    99+
    2022-06-06
    自定义 示例 dialog Android
  • C#实现自定义屏保的示例代码
    目录实践过程效果代码实践过程 效果 代码 public partial class Form1 : Form { public Form1() { ...
    99+
    2022-12-31
    C#自定义屏保 C# 屏保
  • Flutter仿微信通讯录实现自定义导航条的示例代码
    某些页面比如我们在选择联系人或者某个城市的时候需要快速定位到我们需要的选项,一般都会需要像微信通讯录右边有一个导航条一样的功能,由A到Z进行快速定位,本篇文章我们将自己来实现一个跟微...
    99+
    2024-04-02
  • Android 自定义View 密码框实例代码
    暴露您view中所有影响可见外观的属性或者行为。 •通过XML添加和设置样式 •通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 ...
    99+
    2022-06-06
    view 自定义view Android
  • c++ qt自定义搜索编辑框的实现方法
    目录自定义LineEdit主界面代码其它说明实现效果如下: 实现方法说明:(1)自定义QLineEdit,在编辑框里添加布局,将按钮设置在右边(2)给自定义QLineEdit添加信...
    99+
    2024-04-02
  • android自定义对话框实例代码
    1.实现效果    2.定义dialog.xml (res/layout/dialog.xml) <?xml version="1.0" encoding="utf...
    99+
    2024-04-02
  • Python+Flask实现自定义分页的示例代码
    目录前言后端后端思路后端代码前端前端思路前端代码前言 分页操作在web开发中几乎是必不可少的,而我们的flask不像django自带封装好的分页操作,要分页则需要依赖flask-sq...
    99+
    2024-04-02
  • 自定义搜索功能Android实现
    先看看效果图: 源码下载:自定义搜索功能 代码: SearchActivity.java package com.bzu.gxs.search.activity; impo...
    99+
    2022-06-06
    自定义 Android
  • Java实现二分搜索树的示例代码
    目录1.概念2.重点操作3.完整代码1.概念 a.是个二叉树(每个节点最多有两个子节点) b.对于这棵树中的节点的节点值 左子树中的所有节点值 < 根节点 < 右子树的所...
    99+
    2024-04-02
  • react+antdselect下拉框实现模糊搜索匹配的示例代码
    我们在开发过程中,经常会出现下拉框数据很多得情况,这个时候客户一个个得找就很浪费时间,那该怎么办呢? 我们可以实现一边输入一遍模糊匹配。 实现后的效果是 具体代码实现请看下面: ...
    99+
    2023-01-31
    react antd select模糊搜索 react antd select下拉框
  • Flutter实现自定义筛选框的方法
    本篇内容主要讲解“Flutter实现自定义筛选框的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Flutter实现自定义筛选框的方法”吧!目录一、首先自定义筛选框的按钮视图,布局很简单,一个...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作