主流框架对比
- 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环境安装
安装jdk、配置jdk环境变量
下载Flutter SDK、flutter环境变量配置(可以在终端直接使用flutter命令)
开发工具:Android Studio 或 VS Code
flutter sdk下flutter_console.bat双击运行并启动flutter命令行。就可以在Flutter命令行运行flutter命令了。
进行Flutter doctor的测试
在终端中输入 flutter doctor进行检测
出现
X Android SDK is missing command line tools;...需要安装Android Studio
AS(Android Studio)配置Flutter插件:File–Settings–Plugin搜索Flutter,点击安装,重启
再打开终端,输入
flutter doctor --android-licenses,安装Android证书
安装AVD虚拟机
- 现在需要一个虚拟机来运行我们的程序,可以点击Android Studio中的上方菜单
tool-AVD Manager选项。 - 出现新建菜单,选择
Create Virtual Device.....,如果你一个虚拟机也没建过,这个选项在对话框的中间(我一定跟我的图一样)。 - 选择虚拟机类型,这个你随意选就好,我选择的是
Nexus 5x。(如果你屏幕小,就选择一个小屏幕的虚拟机) - 选择系统,这里尽量选择最新的,我选择了
Android 9.0系统,选择好后,又是一个漫长的等待过程。 - 安装好后,点击开始按钮,运行虚拟机了(第一次运行,需要安装系统,会慢一些)。
若是直接用真机的话可以不用安装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扩展包含了一些常用的代码片段
stlessStatelessWidgetstfullStatefulWidgetstanimStatefulWidget with AnimationController
我们也可以增加自己自定义的代码片段
- 在控制台输入
Configure User Snippets/ 首选项:配置用户代码片段 - 选择
dart.json - 编写自己的代码片段
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、布局layoutmain 调用的
MyApp中要有MaterialApp,否则会报错。在
MaterialApp中可以设置主题,控制应用程序的外观和风格在
MaterialApp中至少要创建一个home或routes或onGenerateRoute或builderScaffold是Material library中提供的一个widget,它提供了默认的导航栏,标题和包含主屏幕 widget树(可以很复杂)的 body 属性。StatefulWidget有状态的部件持有的状态可能在
Widget生命周期中发生变化,实现一个 stateful widget 至少需要两个类:StatefulWidget类、State类。StatefulWidget类本身是不变的,但是State类在widget生命周期中始终存在widget主要工作是提供一个build()方法来描述如何根据其他较低级别的widget来显示自己。ThemeData属性及描述属性名 类型 说明 accentColorColor前景色(文本、按钮等) accentColorBrightnessBrightness``accentColor 的亮度。用于确定放置在突出颜色顶部的文本和图标的颜色(例如FloatingButton`上的图标)accentIconThemeIconThemeData与突出颜色对照的图片主题 accentTextThemeTextTheme与突出颜色对照的文本主题 backgroundColorColor与 primaryColor对比的颜色(例如:用作进度条的剩余部分)bottomAppBarColorColorBottomAppBar的默认颜色brightnessBrightness应用程序整体主题的亮度。由按钮等 Widget使用buttonColorColorMaterial中RaisedButtons使用的默认填充色ButtonThemeButtonThemeData定义了按钮等空间的默认配置,如 RaisedButton和FlatButtoncanvasColorColorMaterialType.canvas Material的默认颜色chipThemeChiipThemeData用于渲染 Chip的颜色和样式dialogBackgroundColorColorDialog原色的背景色disabledColorColor用于 Widget无效的颜色,包括任何状态。例如禁用复选框dividerColorColorDividers和PopupMenuDividers的颜色。也用于ListTiles中间和DataTables的每行中间errorColorColor用于输入验证错误的颜色。例如在 TextField中hashCodeint对象的哈希值 highlightColorColor用于类似墨水喷溅动画或指示菜单被选中的高亮颜色 iconThemeIconThemeData与卡片和画布颜色形成对比的图标主题 indicatorColorColorTabBar中选项选中的指示器颜色inputDecorationThemeInpputDecorationThemeInputDecorator、TextField和TextFormField的默认InputDecoration值基于此主题platformTargetPlatformWidget需要适配的目标类型primaryColorColorApp主要部分的背景色(ToolBar、tabbar等)primaryColorBrightnessBrightnessprimaryColor的亮度primaryColorDarkColorprimaryColor的较暗版本primaryColorLightColorprimaryColor的较亮版本primaryIconThemeIconThemeData一个与主色对比的图片主题 primaryTextThemeTextThemeData一个与主色对比的文本主题 scaffoldBackgroundColorColor作为 Scaffold 基础的 Material 默认颜色,典型 Material 应用或应用内页面的背景颜色 secondaryHeaderColorColor有选定行时 PaginatedDataTable标题的颜色selectedRowColorColor选中行时的高亮颜色 sliderThemeSliderThemeData用于渲染 Slider的颜色和形状splashColorColor墨水喷溅的颜色 splashFactoryInteractiveFeatureFactory定义 InkWall和InkResponse生成的墨水喷溅的外观textSelectionColorColor文本字段中选中文本的颜色。例如 TextFieldtextSelectionHandleColorColor用于调整当前文本的哪个部分的句柄颜色 textThemeTextTheme与卡片和画布对比的文本颜色 toggleableActiveColorColor用于突出显示切换 Widget(如Switch、Radio和Checkbox)的活动状态的颜色unselectedWidgetColorColor用于 Widget处于非活动(但已启用)状态的颜色。例如,未选中的复选框。通常与accentColor形成对比runtimeTypeType表示对象的运行时类型
局部主题:创建特有的主题数据或扩展父主题。
创建特有的主题数据
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:core、dart:html、dart:io)包名 描述 dart:async异步编程支持,提供 Future 和 Stream 类 dart:collection对 dart:core 提供更多的集合支持 dart:convert不同类型(JSON,UTF-8)间的字符编码、解码支持 dart:coreDart 语言内建的类型、对象以及 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 至少需要两个类:
- 一个
StatefulWidget类。 - 一个
State类。StatefulWidget类本身是不变的,但是 State类在widget生命周期中始终存在。
pubspec
pubspec文件管理Flutter应用程序的assets(资源,如图片、package等)
架构设计

Framework
一个纯 Dart实现的 SDK,类似于 React在 JavaScript中的作用。它实现了一套基础库, 用于处理动画、绘图和手势。并且基于绘图封装了一套 UI组件库,然后根据 Material 和Cupertino两种视觉风格区分开来。这个纯 Dart实现的 SDK被封装为了一个叫作 dart:ui的 Dart库。我们在使用 Flutter写 App的时候,直接导入这个库即可使用组件等功能。
Engine
一个纯 C++实现的 SDK,其中囊括了 Skia引擎、Dart运行时、文字排版引擎等。不过说白了,它就是 Dart的一个运行时,它可以以JIT、JIT 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 组件页面状态切换后保持住:派生出
PageState加with AutomaticKeepAliveClientMixin,重写bool get wantKeepAlive=>true;搜索条:
onpress中加 showSearch(context:context, delegate:派生 SearchDelegate());会开启一个新页面派生
SearchDelegate中buildActions右侧icon、buildLeading左侧icon、buildResults搜索结果、buildSuggestions搜索建议Wrap流式布局
展开闭合
ExpansionTile、列表带展开闭合ExpansionPanelList画曲线:
ClipPath内 clipper:派生CustomClipper<Path>,贝塞尔曲线要确定4 个范围点+控制点+结束点。可以画多条曲线闪屏动画:派生 State,自定义
AnimationController用来控制时长、动画播放。Animation 用来设置动画并加 status 监听,结束就跳转右滑返回:页面导入
cupertino.dart而不是material.dart,用CupertinoPageScaffold脚手架+CupertinoButton+CupertinoPageRoute轻量级提示:
Tooltip(长按的时候会有提示)拖拽效果:自定义个
DraggableWidget extends StatefulWidgetPositioned页面脚手架中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<double> animation,
Animation<double> secondaryAnimation) {
return Center(
child: Container(
height: 300,
width: 250,
color: Colors.lightGreenAccent,
),
);
});
barrierDismissible:是否可以点击背景关闭。
barrierColor:背景颜色
transitionDuration:动画时长,
transitionBuilder是构建进出动画,默认动画是渐隐渐显,构建缩放动画代码如下:
showGeneralDialog(
transitionBuilder: (BuildContext context, Animation<double> animation,
Animation<double> 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: <Widget>[
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个按钮根据应用程序支持的语言显示相应的语言,比如显示中文方法如下:
- 在
pubspec.yaml中配置支持国际化:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
- 在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: <Widget>[
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: <PopupMenuEntry>[
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<String>{
@override
List<Widget> 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<Widget> 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,
);
}