flutter笔记

主流框架对比

  • Cordova:Cordova基于网页技术进行包装,利用插件的形式开发移动应用的,这点的性能和体验,Flutter完胜
  • RN(React Native):RN的效率是由于将View编译成原生View,效率上比Cordova的HTML5高很多,但它也有效率问题:RN的渲染机制是基于前端框架的考虑,复杂UI的渲染需要依赖多个View叠加。比如渲染个复杂的ListView,每个小控件都是个native的View,然后相互组合叠加,若此时我们滑动刷新则会有很多个对象需要渲染,也就是说RN的列表方案不友好。
  • Flutter:吸收了前两者的教训,在渲染技术上选择自己实现(GDI),有更好的可控性,使用了新语言Dart,避免了RN那种通过桥接器JavaScript通讯导致效率底下的问题,故在性能方面比RN高。另外,打开Android手机开发者选项里的显示边界布局,可以发现Flutter的布局是一个整体,说明Flutter的渲染没有使用原生控件。

Flutter采用GPU渲染技术,性能更高,其编写的应用可以达到120fps(每秒传输帧数),完全可以胜任游戏的制作。RN的性能只能达到60fps。

Flutter丰富的插件

Flutter环境安装

  • 安装jdk、配置jdk环境变量

  • 下载Flutter SDK、flutter环境变量配置(可以在终端直接使用flutter命令)

  • 开发工具:Android Studio 或 VS Code

flutter sdk下flutter_console.bat双击运行并启动flutter命令行。就可以在Flutter命令行运行flutter命令了。

进行Flutter doctor的测试

在终端中输入 flutter doctor进行检测

  1. 出现X Android SDK is missing command line tools;...

    需要安装Android Studio

    AS(Android Studio)配置Flutter插件:File–Settings–Plugin搜索Flutter,点击安装,重启

  2. 再打开终端,输入flutter doctor --android-licenses,安装Android证书

安装AVD虚拟机

  1. 现在需要一个虚拟机来运行我们的程序,可以点击Android Studio中的上方菜单tool -AVD Manager选项。
  2. 出现新建菜单,选择Create Virtual Device.....,如果你一个虚拟机也没建过,这个选项在对话框的中间(我一定跟我的图一样)。
  3. 选择虚拟机类型,这个你随意选就好,我选择的是Nexus 5x。(如果你屏幕小,就选择一个小屏幕的虚拟机)
  4. 选择系统,这里尽量选择最新的,我选择了Android 9.0系统,选择好后,又是一个漫长的等待过程。
  5. 安装好后,点击开始按钮,运行虚拟机了(第一次运行,需要安装系统,会慢一些)。

若是直接用真机的话可以不用安装AVD虚拟机

使用Android Studio开发Flutter

使用VSCode开发Flutter

  • 在终端运行flutter doctor,查看输出是否有问题

  • 或在VS Code的命令面板找到Flutter:Run Flutter Doctor,执行

    VSCode命令面板(cmd+shift+p)支持搜索,输入flutter搜索我们需要的命令

新建Flutter项目

  • 在终端输入flutter create
  • 或在VSCode命令面板,找到Flutter :New Project执行

VSCode运行Flutter项目

在VSCode的终端输入flutter run

运行Flutter项目

  • 调试->启用调试(F5)

可以在命令面板送找到Debug:Select and Start Debugging执行->选择添加配置->选择Dart&Flutter,这样就不用每次都选调试环境了。 也可以在调试界面 选择小齿轮 选择Dart&Flutter

hot reload

  • save(cmd+s)
  • 或者点击绿色圆形箭头按钮

选择调试设备

  • 在界面右下角可以选择设备

  • 或者命令面板 找到Flutter: Select Devices

视图调试

在运行flutter的时候打开命令面板输入 Flutter:Toggle即可看到熟悉的命令

  • Toggle Baseline Painting
  • Toggle Repaint Rainbow
  • Toggle Slow Animations
  • Toggle Slow-Mode Banner

Observatory

命令面板 Dart: Open Observatory

调试控制台

很多时候VSCode开发体验都蛮好的,但是调试控制台真的难用,还不支持搜索。 不过我们可以设置flutter log输出文件,用其他软件来看log。

  • 在用户设置中搜索 flutter run log 中设置

  • 用其他软件打开这个文件 比如自带的控制台open -a Console .vscode/run.log

Assists & Quick Fixes

  • 命令面板 Quick fix或者快速修复(没错支持中文输入=。=)
  • 或者使用快捷键cmd + .

Sort Members

  • 命令面板 Sort Members
  • 或者 右键->源代码操作->Sort Members
  • 也可以自定义Sort Members的快捷键

Organize Imports

  • 命令面板Organize Imports
  • 或者 右键->源代码操作->Organize Imports
  • 或者 快捷键shift + option + o

格式化(Fotmat Document)

  • 命令面板Fotmat Document
  • 或者 右键->设置文档的格式
  • 或者 快捷键 shift + option + f

Go to Definition

  • 右键 转到定义
  • 快捷键f12 或者 cmd+左键

Find All References

  • 右键 Find All References

代码片段

Flutter扩展包含了一些常用的代码片段

  • stlessStatelessWidget
  • stfullStatefulWidget
  • stanimStatefulWidget with AnimationController

我们也可以增加自己自定义的代码片段

  1. 在控制台输入Configure User Snippets/ 首选项:配置用户代码片段
  2. 选择dart.json
  3. 编写自己的代码片段

这是我们写的代码片段可做参考

Flutter打包

生成keystore

VSCode终端:keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

其中~/key.jks要改成我们自己的盘,比如e:\key.jks

flutter doctor -v

这个命令可以找到keytool.exe位置

新建key.properties

在android根目录下新建key.properties,内容:

storePassword=123123
keyPassword=123123
keyAlias=key
storeFile=E:/key.jks

app/build.gradle下配置这个签名文件

android{ 这行前面加上

def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

把如下代码进行替换

buildTypes {
    release {
        signingConfig signingConfigs.debug
    }
}

替换成的代码:

signingConfigs {
    release {
        keyAlias keystoreProperties['keyAlias']
        keyPassword keystoreProperties['keyPassword']
        storeFile file(keystoreProperties['storeFile'])
        storePassword keystoreProperties['storePassword']
    }
}
buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}

生成apk

直接在终端中输入:

flutter build apk

这时候就打包成功了,剩下的安装过程我就省略

基础

  • Flutter:包含Flutter的引擎、框架、Widget、工具和Dart SDK

  • Material 是一种标准的移动端和 web 端的视觉设计语言。

  • main 函数使用了=>符号,这是 Dart 中单行函数或方法的简写

  • MyApp 该应用程序继承了 StatelessWidget,这将会使应用本身也成为一个 Widget。在 Flutter 中,大多数东西都是 widget,包括对齐alignment、填充padding、布局layout

  • main 调用的 MyApp 中要有 MaterialApp,否则会报错。

    MaterialApp 中可以设置主题,控制应用程序的外观和风格

    MaterialApp 中至少要创建一个 homeroutesonGenerateRoutebuilder

    ScaffoldMaterial library 中提供的一个 widget,它提供了默认的导航栏,标题和包含主屏幕 widget树(可以很复杂)的 body 属性。

  • StatefulWidget 有状态的部件

    持有的状态可能在 Widget 生命周期中发生变化,实现一个 stateful widget 至少需要两个类:StatefulWidget类、State 类。StatefulWidget 类本身是不变的,但是 State 类在 widget 生命周期中始终存在

  • widget 主要工作是提供一个build()方法来描述如何根据其他较低级别的 widget 来显示自己。

  • ThemeData 属性及描述

    属性名 类型 说明
    accentColor Color 前景色(文本、按钮等)
    accentColorBrightness Brightness ``accentColor的亮度。用于确定放置在突出颜色顶部的文本和图标的颜色(例如FloatingButton`上的图标)
    accentIconTheme IconThemeData 与突出颜色对照的图片主题
    accentTextTheme TextTheme 与突出颜色对照的文本主题
    backgroundColor Color primaryColor 对比的颜色(例如:用作进度条的剩余部分)
    bottomAppBarColor Color BottomAppBar 的默认颜色
    brightness Brightness 应用程序整体主题的亮度。由按钮等 Widget 使用
    buttonColor Color MaterialRaisedButtons使用的默认填充色
    ButtonTheme ButtonThemeData 定义了按钮等空间的默认配置,如 RaisedButtonFlatButton
    canvasColor Color MaterialType.canvas Material的默认颜色
    chipTheme ChiipThemeData 用于渲染 Chip 的颜色和样式
    dialogBackgroundColor Color Dialog 原色的背景色
    disabledColor Color 用于 Widget 无效的颜色,包括任何状态。例如禁用复选框
    dividerColor Color DividersPopupMenuDividers 的颜色。也用于 ListTiles 中间和 DataTables 的每行中间
    errorColor Color 用于输入验证错误的颜色。例如在 TextField
    hashCode int 对象的哈希值
    highlightColor Color 用于类似墨水喷溅动画或指示菜单被选中的高亮颜色
    iconTheme IconThemeData 与卡片和画布颜色形成对比的图标主题
    indicatorColor Color TabBar 中选项选中的指示器颜色
    inputDecorationTheme InpputDecorationTheme InputDecoratorTextFieldTextFormField 的默认 InputDecoration 值基于此主题
    platform TargetPlatform Widget 需要适配的目标类型
    primaryColor Color App 主要部分的背景色(ToolBartabbar 等)
    primaryColorBrightness Brightness primaryColor 的亮度
    primaryColorDark Color primaryColor 的较暗版本
    primaryColorLight Color primaryColor 的较亮版本
    primaryIconTheme IconThemeData 一个与主色对比的图片主题
    primaryTextTheme TextThemeData 一个与主色对比的文本主题
    scaffoldBackgroundColor Color 作为 Scaffold 基础的 Material 默认颜色,典型 Material 应用或应用内页面的背景颜色
    secondaryHeaderColor Color 有选定行时 PaginatedDataTable 标题的颜色
    selectedRowColor Color 选中行时的高亮颜色
    sliderTheme SliderThemeData 用于渲染 Slider 的颜色和形状
    splashColor Color 墨水喷溅的颜色
    splashFactory InteractiveFeatureFactory 定义 InkWallInkResponse 生成的墨水喷溅的外观
    textSelectionColor Color 文本字段中选中文本的颜色。例如 TextField
    textSelectionHandleColor Color 用于调整当前文本的哪个部分的句柄颜色
    textTheme TextTheme 与卡片和画布对比的文本颜色
    toggleableActiveColor Color 用于突出显示切换 Widget(如 SwitchRadioCheckbox)的活动状态的颜色
    unselectedWidgetColor Color 用于 Widget 处于非活动(但已启用)状态的颜色。例如,未选中的复选框。通常与 accentColor 形成对比
    runtimeType Type 表示对象的运行时类型
  • 局部主题:创建特有的主题数据或扩展父主题。

    • 创建特有的主题数据

      new Theme(
          //创建一个特有的主题数据
          data:new ThemeData(
              accentColor: Colors.yellow,
          ),
          child: new FloatingActionButton(
              onPressed:(){},
              child:new Icon(Icons.add),
          ),
      );
      
    • 扩展父主题(无须覆盖所有的主题属性,用 copyWith)

      new Theme(
          //覆盖 accentColor 为 Colors.yellow
          data: Theme.of(context).copyWith(accentColor: Colors.yellow),
          child: new FloatingActionButton(
              onPressed: null,
              child: new Icon(Icons.add),
          ),
      );
      
  • Theme.of(context)可通过上下文获取主题,查找最近的主题,若找不到就会找整个应用的主题。

  • 第三方库如:网络请求(http)、自定义导航/路由处理(fluro)、集成设备 API(如 url_launcher&battery)以及第三方平台SDK(如 Firebase)等

  • 关键字(56个):abstract、do、import、super、as、dynamic、in、switch、assert、else、interface、sync、enum、implement、is、this、async、export、library、throw、await、external、mixin、true、break、extends、new、try、case、factory、null、typedef、catch、false、operator、var、class、final、part、void、const、finally、rethrow、while、continue、for、return、with、covariant、get、set、yield*、default、if、static、deferred

  • Dart 语言常用库(使用频率最高 dart:coredart:htmldart:io)

    包名 描述
    dart:async 异步编程支持,提供 Future 和 Stream 类
    dart:collection 对 dart:core 提供更多的集合支持
    dart:convert 不同类型(JSON,UTF-8)间的字符编码、解码支持
    dart:core Dart 语言内建的类型、对象以及 dart 语言核心的功能
    dart:html 网页开发用到的库
    dart:io 文件读写 I/O 相关操作的库
    dart:math 数字常量及函数,提供随机数算法
    dart:svg 事件和动画的矢量图像支持
  • final和const的区别

    final wordPair = WordPair.random();
    

    final表明这个变量不能再发生更改,但初始值在编译期是不确定的,在运行时赋值后就不能再更改了。

    const city = "烟台";
    

    const定义时需要是个明确的值,在编译时就知道值了。

符号

=>

Dart中单行函数或方法的简写

??

Dart中表示 if null

//如果b为null则a=hello,否则a=b
String a = b ?? 'hello'

Widget

Flutter中大多数是widget,包含对齐(alignment)、填充(padding)和布局(layout)
widget的主要工作是提供一个build()方法来描述如何根据其他较低级别的widget来显示自己Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终(final)的.Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:

  1. 一个 StatefulWidget类。
  2. 一个 State类。 StatefulWidget类本身是不变的,但是 State类在widget生命周期中始终存在。

pubspec

pubspec文件管理Flutter应用程序的assets(资源,如图片、package等)

架构设计

flutter笔记_第1张图片

Framework

一个纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用。它实现了一套基础库, 用于处理动画、绘图和手势。并且基于绘图封装了一套 UI组件库,然后根据 Material 和Cupertino两种视觉风格区分开来。这个纯 Dart实现的 SDK被封装为了一个叫作 dart:ui的 Dart库。我们在使用 Flutter写 App的时候,直接导入这个库即可使用组件等功能。

Engine

一个纯 C++实现的 SDK,其中囊括了 Skia引擎、Dart运行时、文字排版引擎等。不过说白了,它就是 Dart的一个运行时,它可以以JITJIT Snapshot 或者 AOT的模式运行 Dart代码。在代码调用 dart:ui库时,提供 dart:ui库中 Native Binding 实现。 不过别忘了,这个运行时还控制着 VSync信号的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码。

网络

Dio是Flutter下热门的网络请求框架之一

JSPang13 个 demos

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

    其中 main()是主函数,是程序的入口

    flutter 1.0 后就可以省略 new

  • 要调用其他dart 文件的 class 需要在调用的类中加 import ‘文件路径’;

  • Scaffold是页面脚手架

  • list..add(widget 实例)..add(widget 实例);可以使用..来给集合连续添加元素

  • StatefulWidget 要调用 setState(){}才可以更新内容

  • BottomNavigationBarItem 是底部导航栏

  • FloatingActionButton 是浮动的按钮

  • Navigator页面跳转 push,跳转后返回的回调 pop

  • 页面跳转加动画,派生出 PageRouteBuilder 在其构造方法中加动画

  • 毛玻璃效果:写个约束盒子组件ConstrainedBox(放图),再写个可裁切的矩形 ClipRect 覆盖在上方(在背景过滤器BackdropFilter中加半透明、宽高、装饰器BoxDeration等)

  • 上部的导航栏:在 AppBar 中添加多个 Tab 组件

  • 页面状态切换后保持住:派生出 PageStatewith AutomaticKeepAliveClientMixin,重写 bool get wantKeepAlive=>true;

  • 搜索条:onpress 中加 showSearch(context:context, delegate:派生 SearchDelegate());会开启一个新页面

    派生 SearchDelegatebuildActions 右侧iconbuildLeading 左侧iconbuildResults 搜索结果、buildSuggestions 搜索建议

  • Wrap流式布局

  • 展开闭合 ExpansionTile、列表带展开闭合ExpansionPanelList

  • 画曲线:ClipPath 内 clipper:派生CustomClipper,贝塞尔曲线要确定4 个范围点+控制点+结束点。可以画多条曲线

  • 闪屏动画:派生 State,自定义 AnimationController 用来控制时长、动画播放。Animation 用来设置动画并加 status 监听,结束就跳转

  • 右滑返回:页面导入 cupertino.dart 而不是 material.dart,用 CupertinoPageScaffold 脚手架+CupertinoButton+CupertinoPageRoute

  • 轻量级提示:Tooltip(长按的时候会有提示)

  • 拖拽效果:自定义个DraggableWidget extends StatefulWidget

    Positioned页面脚手架中 Draggable (feedback 拖动控件的时候子元素的样式、onDraggableCanceled 松手的时候)。外面调用这个自定义的 DraggableWidget 传不同的值即可

代码

去除右上角“Debug”字样

在(SatelessWidget)MyApp的build的return中 添加 //去除右上角的debug字样 debugShowCheckedModeBanner: false,

void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context){
        return new MaterialApp(
        	...
            //去除右上角的debug字样
            debugShowCheckdModeBanner: false,
            ...
        );
    }
}

flutter内置了10多种show

showDialog

常用的提示弹窗(带标题、提示内容、取消按钮、确认按钮)

showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        ...
      );
    }
);

关闭对话框需要使用

Navigator.of(context, rootNavigator: true).pop(result)

而不是

Navigator.pop(context, result)

showCupertinoDialog

ios风格的提示弹窗(带标题、提示内容、取消按钮、确认按钮)

showCupertinoDialog(
    context: context,
    builder: (context) {
      return CupertinoAlertDialog(
       ...
      );
    });

builder 通常返回 CupertinoDialog 或者 CupertinoAlertDialog

showGeneralDialog

自定义弹窗

showGeneralDialog(
    context: context,
    barrierDismissible:true,
    barrierLabel: '',
    transitionDuration: Duration(milliseconds: 200),
    pageBuilder: (BuildContext context, Animation animation,
        Animation secondaryAnimation) {
      return Center(
        child: Container(
          height: 300,
          width: 250,
          color: Colors.lightGreenAccent,
        ),
      );
    });

barrierDismissible:是否可以点击背景关闭。

barrierColor:背景颜色

transitionDuration:动画时长,

transitionBuilder是构建进出动画,默认动画是渐隐渐显,构建缩放动画代码如下:

showGeneralDialog(
    transitionBuilder: (BuildContext context, Animation animation,
        Animation secondaryAnimation, Widget child) {
      return ScaleTransition(scale: animation, child: child);
    },
    ...
  )

showAboutDialog

AboutDialog用于描述当前App信息,底部提供2个按钮:查看许可按钮和关闭按钮。AboutDialog需要和showAboutDialog配合使用,用法如下:

showAboutDialog(
  context: context,
  applicationIcon: Image.asset(
    'images/bird.png',
    height: 100,
    width: 100,
  ),
  applicationName: '应用程序',
  applicationVersion: '1.0.0',
  applicationLegalese: 'copyright 老孟,一枚有态度的程序员',
  children: [
    Container(
      height: 30,
      color: Colors.red,
    ),
    Container(
      height: 30,
      color: Colors.blue,
    ),
    Container(
      height: 30,
      color: Colors.green,
    )
  ],
);

属性说明如下:

  • applicationIcon:应用程序的图标。
  • applicationName:应用程序名称。
  • applicationVersion:应用程序版本。
  • applicationLegalese:著作权(copyright)的提示。
  • children:位置如上图的红蓝绿色的位置。

所有的属性都需要手动设置,不是自动获取的。

下面的2个按钮根据应用程序支持的语言显示相应的语言,比如显示中文方法如下:

  1. pubspec.yaml中配置支持国际化:
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  1. 在MaterialApp中配置当前区域:
MaterialApp(
      title: 'Flutter Demo',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('zh', 'CH'),
        const Locale('en', 'US'),
      ],
      locale: Locale('zh'),
      ...
  )复制代码

showLicensePage

此控件基本不会用到,浏览一下即可。

LicensePage用于描述当前App许可信息,LicensePage需要和showLicensePage配合使用,用法如下:

showLicensePage(
  context: context,
  applicationIcon: Image.asset(
    'images/bird.png',
    height: 100,
    width: 100,
  ),
  applicationName: '应用程序',
  applicationVersion: '1.0.0',
  applicationLegalese: 'copyright 老孟,一枚有态度的程序员',
);

页面中下面的英文我们是无法更改的

showBottomSheet

在最近的Scaffold父组件上展示一个material风格的bottom sheet,位置同Scaffold组件的bottomSheet,如果Scaffold设置了bottomSheet,调用showBottomSheet抛出异常。

基本用法如下:

showBottomSheet(
    context: context,
    builder: (context) {
      return Container(height: 200, color: Colors.lightBlue);
    });

设置其背景颜色、阴影值、形状:

showBottomSheet(
    context: context,
    backgroundColor: Colors.lightGreenAccent,
    elevation:20,
    shape: CircleBorder(),
    builder: (context) {
      return Container(height: 200);
    });

showModalBottomSheet

从底部弹出,通常和BottomSheet配合使用,用法如下:

showModalBottomSheet(
        context: context,
        builder: (BuildContext context) {
          return BottomSheet(...);
        });

设置背景、阴影、形状:

showModalBottomSheet(
    context: context,
    backgroundColor: Colors.lightBlue,
    elevation: 10,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
    ...
  )

isDismissible:是否可以点击背景关闭。

isScrollControlled参数指定是否使用可拖动的可滚动的组件,如果子组件是ListView或者GridView,此参数应该设置为true,设置为true后,最大高度可以占满全屏。用法如下:

showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (BuildContext context) {
      return ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('老孟$index'),
          );
        },
        itemExtent: 50,
        itemCount: 50,
      );
    });复制代码

showCupertinoModalPopup

showCupertinoModalPopup 展示ios的风格弹出框,通常情况下和CupertinoActionSheet配合使用,用法如下:

showCupertinoModalPopup(
    context: context,
    builder: (BuildContext context) {
      return CupertinoActionSheet(
        title: Text('提示'),
        message: Text('是否要删除当前项?'),
        actions: [
          CupertinoActionSheetAction(
            child: Text('删除'),
            onPressed: () {},
            isDefaultAction: true,
          ),
          CupertinoActionSheetAction(
            child: Text('暂时不删'),
            onPressed: () {},
            isDestructiveAction: true,
          ),
        ],
      );
    }
);

filter参数可以对弹出框以外的区域做模糊或者矩阵操作,用法如下:

showCupertinoModalPopup(
    context: context,
    filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
    ...
  )

弹出框以外的区域有毛玻璃的效果。

showMenu

showMenu弹出一个Menu菜单,用法如下:

showMenu(
    context: context,
    position: RelativeRect.fill,
    items: [
      PopupMenuItem(child: Text('语文')),
      PopupMenuDivider(),
      CheckedPopupMenuItem(
        child: Text('数学'),
        checked: true,
      ),
      PopupMenuDivider(),
      PopupMenuItem(child: Text('英语')),
    ]);复制代码

position参数表示弹出的位置

弹出的位置在屏幕的左上角,我们希望弹出的位置在点击按钮的位置,因此需要计算按钮的位置,计算如下:

final RenderBox button = context.findRenderObject();
final RenderBox overlay = Overlay.of(context).context.findRenderObject();
final RelativeRect position = RelativeRect.fromRect(
  Rect.fromPoints(
    button.localToGlobal(Offset(0, 0), ancestor: overlay),
    button.localToGlobal(button.size.bottomRight(Offset.zero),
        ancestor: overlay),
  ),
  Offset.zero & overlay.size,
);复制代码

你需要将按钮单独封装为StatefulWidget组件,否则context代表的就不是按钮组件。

showSearch

showSearch 是直接跳转到搜索页面,用法如下:

showSearch(context: context, delegate: CustomSearchDelegate());

class CustomSearchDelegate extends SearchDelegate{
  @override
  List buildActions(BuildContext context) {
    return null;
  }

  @override
  Widget buildLeading(BuildContext context) {
    return null;
  }

  @override
  Widget buildResults(BuildContext context) {
    return null;
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return null;
  }

}复制代码

使用showSearch,首先需要重写一个SearchDelegate,实现其中的4个方法。

buildLeading表示构建搜索框前面的控件,一般是一个返回按钮,点击退出,代码如下:

@override
Widget buildLeading(BuildContext context) {
  return IconButton(
    icon: Icon(Icons.arrow_back,color: Colors.blue,),
    onPressed: (){
      close(context, '');
    },
  );
}

buildSuggestions是用户正在输入时显示的控件,输入框放生变化时回调此方法,通常返回一个ListView,点击其中一项时,将当前项的内容填充到输入框,用法如下:

@override
Widget buildSuggestions(BuildContext context) {
  return ListView.separated(
    itemBuilder: (context, index) {
      return ListTile(
        title: Text('老孟 $index'),
        onTap: () {
          query = '老孟 $index';
        },
      );
    },
    separatorBuilder: (context, index) {
      return Divider();
    },
    itemCount: Random().nextInt(5),
  );
}

buildActions输入框后面的控件,一般情况下,输入框不为空,显示一个清空按钮,点击清空输入框:

@override
List buildActions(BuildContext context) {
  return [
    IconButton(
      icon: Icon(
        Icons.clear,
      ),
      onPressed: () {
        query = '';
      },
    )
  ];
}复制代码

buildResults是构建搜索结果控件,当用户点击软键盘上的“Search”时回调此方法,一般返回ListView,用法如下:

@override
Widget buildResults(BuildContext context) {
  return ListView.separated(
    itemBuilder: (context, index) {
      return Container(
        height: 60,
        alignment: Alignment.center,
        child: Text(
          '$index',
          style: TextStyle(fontSize: 20),
        ),
      );
    },
    separatorBuilder: (context, index) {
      return Divider();
    },
    itemCount: 10,
  );
}

你可能感兴趣的:(android,dart,java,app,epoll)