app开发者平台在数字化时代的重要性与发展趋势解析
708
2022-11-17
Flutter 学习 Basics Widget
文章目录
1. 概述2. 常用组件
2.1 Text
2.1.1 TextStyle2.1.2 TextSpan2.1.3 DefaultTextStyle2.1.4 使用字体
2.2 Button
2.2.1 ElevatedButton2.2.2 TextButton2.2.3 OutlinedButton2.2.4 IconButton2.2.5 带图标的按钮
2.3 图片及Icon
2.3.1 图片
2.3.1.1 ImageProvider2.3.1.2 Image Widget2.3.1.3 Image 参数
2.3.2 Icon
2.4 单选开关和复选框
2.4.1 属性
2.5 输入框以及表单
2.5.1 输入框 TextField
2.5.1.1 属性2.5.1.2 通过 controller 获取输入内容2.5.1.3 通过 controller 监听文本内容变化2.5.1.4 控制焦点2.5.1.5 监听焦点状态改变事件
2.5.2 表单
2.5.2.1 FormField2.5.2.2 FormState2.5.2.3 示例
参考文章
1. 概述
上一篇说到,Basics Widget 并不是 Flutter 的一个专门的Widget类别,而是 Flutter 官方挑选一些开发常用的 Widget 构成的,希望我们掌握到一些最基本的开发能力。
包括:
文本 Text按钮 Button图片 Image单选框、复选框输入框、表单指示器Container…
2. 常用组件
2.1 Text
Text 用于显示简单样式文本,然后可以填充一些文本显示样式的属性,如下例子:
Text("Hello World", textAlign: TextAlign.left, maxLines: 1, overflow: TextOverflow.ellipsis, textScaleFactor: 1.5);
textAlign 文本对齐方式maxLines 、overflow maxLines 指定文本显示的最大行数。 当文本内容超过最大行数时, overflow 指定了阶段方式, 例如 ellipsis 就是将多余的文本用 “…” 表示textScaleFactor 代表文本相对于当前字体大小的缩放因子,想你对于去设置文本的样式 style 属性的 fontSize, 它是调整字体大小的一个快捷方式, 该属性的默认值可以通过 MediaQueryData.textScaleFactor 获得, 如果没有 MediaQuery,那么会默认值为 1.0
2.1.1 TextStyle
TextStyle 用于指定文本样式,例如颜色、字体、粗细、背景等,如下:
@override Widget build(BuildContext context) { return MaterialApp( title: "Flutter", home: Scaffold( appBar: AppBar( title: const Text("Basics Widget"), ), body: Text( "Hello World", style: TextStyle( color: Colors.blue, fontSize: 19.0, height: 2, fontFamily: "Courier", background: Paint()..color = Colors.yellow, decoration: TextDecoration.underline, decorationStyle: TextDecorationStyle.dashed), ))); }
效果如图:
一些属性:
height 行高,它不是一个绝定的值,因为具体的行高为 height*fontSize ,同理行宽也是fontFamily 由于不同平台默认支持的字体集不同,所以在手动指定字体时一定要先在不同平台测试一下fontSize 改属性和 Text 的 textScaleFactor 都用于控制字体大小,但是有两个区别, ①:fontSize 可以精确指定字体大小, 而 textScaleFactor 只能缩放比例 ②: textScaleFactor 主要是用于系统字体大小设置改变时,对Flutter 应用字体进行全局调整,而 fontSzie通常用于单个文本,字体大小不会跟随系统字体大小变化
2.1.2 TextSpan
如果我们需要对Text内容不同部分按照不同的样式显示,就可以使用 TextSpan,代表文本的一个“片段”,看看 TextSpan的定义:
const TextSpan({ this.text, this.children, TextStyle? style, this.recognizer, MouseCursor? mouseCursor, this.onEnter, this.onExit, this.semanticsLabel, this.locale, this.spellOut, })
其中 style 和 text 代表样式和文本内容, children是 List
reconizer 用于表示该文本片段上用于手势进行识别处理,下面我们看一个效果图,然后用 TextSpan 来实现:
body: const Text.rich(TextSpan(children: [ TextSpan(text: "Home: "), TextSpan( text: " style: TextStyle(color: Colors.blue), recognizer: _recognizer ), ]))));
这里的代码,用 TextSpan实现了一个基础文本和一个链接片段
2.1.3 DefaultTextStyle
在 Widget 树中, 文本的样式默认是可以被继承的,因此如果 Widget树的某一个节点处设置一个默认的文本样式,那么该节点的子树所有的文本都会默认使用这个样式,而 DefaultTextStyle 正是用于设置默认文本样式的,看下面例子:
DefaultTextStyle( //1.设置文本默认样式 style: TextStyle( color:Colors.red, fontSize: 20.0, ), textAlign: TextAlign.start, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children:
这里的代码首先设置了一个默认的样式,字体大小为20,、颜色为红色,然后将 DefaultTextStyle 设置给了子树,这样一来 Column 所有子孙 Text 默认都会继承该样式, 除非 Text 设置 inherit: false,如下所示:
2.1.4 使用字体
在 Flutter 中可以使用自定义的字体,或者其他第三方字体, 这里就不介绍配置了,具体可以看官方文档:字体
2.2 Button
Material 组件库提供了多种多样的按钮,他们都是直接或间接对 RawMaterialButton 的包装定制,所以大部分属性都一样。另外 Marterial 库中的按钮都有以下共同点:
2.2.1 ElevatedButton
即 带阴影的按钮, 默认带有阴影和灰色背景,按下后阴影会变大,如下所示:
代码如下:
: ElevatedButton( child: const Text("i am ElevatedButton"), onPressed: () {}, ), ),
2.2.2 TextButton
文本按钮,按下后会有背景色,如下图所示:
2.2.3 OutlinedButton
默认有一个边框,不带阴影且背景透明,按下后,边框颜色会变亮、同时出现背景和阴影,如下图所示:
2.2.4 IconButton
代码设置为:
IconButton( icon: Icon(Icons.eleven_mp), onPressed: () {},),
2.2.5 带图标的按钮
上面学到的 ElevatedButton、 TextButton、 OutlinedButton 都有一个 icon() 的构造函数,这样就可以代入一个图片进去,例如设置:
ElevatedButton.icon( icon: const Icon(Icons.send), label: const Text("发送"), onPressed: () {}, ),
效果为(这里有编码问题,可以无视):
2.3 图片及Icon
2.3.1 图片
可以通过 Image 组件来加载并显示布局, Image 的数据源可以是
asset文件内存网络
2.3.1.1 ImageProvider
ImageProvider 是抽象类,主要定义了图片的获取接口 load(),从不同的数据源获取图片需要实现不同的 ImageProvider,如 AssetImage 是实现了从 Asset 中加载图片, NetworkImage 则实现了从网络中加载图片。
2.3.1.2 Image Widget
Image 组件在构建时有一个必选的 image 参数,它对应一个 ImageProvier,下面分别演示一下如何从 asset 和 网络中加载图片。
1.从 asset 中加载图片 在工程根目录下创建一个 images 目录,并将图片拷贝到该目录。 接下来在 pubspec.yaml 文件的 flutter部分 中,写入(注意缩进):
flutter: .. assets: - assets/images/bobo.jpg
最后在代码中使用:
Image( image: AssetImage("images/bobo.jpg"), width: 100.0,)
就能展示图片。
(不过我这里遇到一个问题,使用手机运行Flutter应用能正常展示图片,但是使用 Chrome 模拟器会报错,不知道是什么原因造成的
2.从网络URL中加载图片 直接使用代码:
Image( image: NetworkImage(" width: 100.0,)
可以正常展示图片。
(不过这里出现了很上面一样的问题,但是使用官方使用的url又能正常展示图片
2.3.1.3 Image 参数
我们可以来看下 Image 的参数,通过这些参数可以控制图片外观、大小、混合效果等。
const Image({ Key? key, required this.image, this.frameBuilder, this.loadingBuilder, this.errorBuilder, this.semanticLabel, this.excludeFromSemantics = false, this.width, this.height, this.color, this.opacity, this.colorBlendMode, this.fit, this.alignment = Alignment.center, this.repeat = ImageRepeat.noRepeat, this.centerSlice, this.matchTextDirection = false, this.gaplessPlayback = false, this.isAntiAlias = false, this.filterQuality = FilterQuality.low, })
2.3.2 Icon
Android中有 svg 矢量图, 而 Flutter 中的也有,就是 Icon,它有下面这些优点:
体积小因为是矢量图,所以拉伸不会影响清晰程度可以通过 TextSpan 和 文本混用可以引用到文本样式
Flutter 默认实现了一套Icon,在 pubspec.yaml 的配置文件可以看到:
flutter: uses-material-design: true
来看下官方的示例代码:
String icons = "";// accessible: 0xe03eicons += "\uE03e";// error: 0xe237icons += " \uE237";// fingerprint: 0xe287icons += " \uE287";Text( icons, style: TextStyle( fontFamily: "MaterialIcons", fontSize: 24.0, color: Colors.green, ),);
效果为:
为了不让开发者码点,Flutter 封装了 IconData 和 Icon来专门显示字体图片,上面的例子也可以用下面方式实现:
Row( mainAxisAlignment: MainAxisAlignment.center, children:
我们也可以使用自定义的字体图标,这里就不赘述了,可以看看官方示例:Icon自定义字体图标
2.4 单选开关和复选框
class SwitchAndCheckBoxTestRoute extends StatefulWidget { @override _SwitchAndCheckBoxTestRouteState createState() => _SwitchAndCheckBoxTestRouteState();}class _SwitchAndCheckBoxTestRouteState extends State
为什么要这样子设计,我的理解是:
将开关、复选框的状态抛给父组件,可以更加灵活,比如在勾选时候做一些网络请求,即异步的操作一般来说,这些item是否选中,是和用户数据关联的,用户数据也不可能是他们的私有状态,所以放在一起管理更好
2.4.1 属性
它们的属性比较简单,常用的有:
activeColor:设置激活状态的颜色tristate: 是否为三态,仅 Checbox有,一般情况下只有 “true” 和 “false”,表示选中和非选中,如果设置了tristate 后,还会增加一个 “null” 状态
此外, Checkbox 不可设置宽高,其大小是自定义的,而 Switch 也仅能设置宽度而已。
2.5 输入框以及表单
Flutter Material组件提供了 输入款TextField 和 表单Form
2.5.1 输入框 TextField
2.5.1.1 属性
来看下 TextField 提供的属性:
const TextField({ ... this.controller, this.focusNode, this.decoration = const InputDecoration(), TextInputType? keyboardType, this.textInputAction, this.textCapitalization = TextCapitalization.none, this.style, this.strutStyle, this.textAlign = TextAlign.start, this.textAlignVertical, this.textDirection, this.readOnly = false, ToolbarOptions? toolbarOptions, this.showCursor, this.autofocus = false, this.obscuringCharacter = '•', this.obscureText = false, this.autocorrect = true, SmartDashesType? smartDashesType, SmartQuotesType? smartQuotesType, this.enableSuggestions = true, this.maxLines = 1, this.minLines, this.expands = false, this.maxLength, this.maxLengthEnforcement, this.onChanged, this.onEditingComplete, this.onSubmitted, this.onAppPrivateCommand, this.inputFormatters, this.enabled, this.cursorWidth = 2.0, this.cursorHeight, this.cursorRadius, this.cursorColor, this.selectionHeightStyle = ui.BoxHeightStyle.tight, this.selectionWidthStyle = ui.BoxWidthStyle.tight, this.keyboardAppearance, this.scrollPadding = const EdgeInsets.all(20.0), this.dragStartBehavior = DragStartBehavior.start, this.enableInteractiveSelection = true, this.selectionControls, this.onTap, this.mouseCursor, this.buildCounter, this.scrollController, this.scrollPhysics, this.autofillHints, this.restorationId, this.enableIMEPersonalizedLearning = true, })
属性比较多,列几个关键的讲解:
一个简单的设置代码如下:
Column(children: const
2.5.1.2 通过 controller 获取输入内容
我们可以通过 onChange 拿到内容。 当然也可以使用 controller 来获取
步骤为:
定义一个controller:
final TextEditingController _tfController = TextEditingController();
然后在 TextFiled 中传入这个 controller
TextField( controller: _tfController, ...)
最后就可以通过 : print(_tfController.text) 来获得输入框的内容
2.5.1.3 通过 controller 监听文本内容变化
可以通过 onChange 来监听文本, controller 可以通过设置-来监听文本,如下:
@override void initState() { super.initState(); _tfController.addListener(() { print(_tfController.text); }); }
controller 的功能更多,除了监听文本,还可以设置默认值、选择文本等,这里就不多赘述。
2.5.1.4 控制焦点
可以使用 FocusNode 和 FocusScopeNode 来控制焦点。默认情况下是由 FocusScope 来管理,可以在这个范围内通过 FocusScopeNode 在输入框之间移动焦点、设置默认焦点。
我们可以通过下面代码来获取当前 Widget 树中默认的 FocusScopeNode:
focusScopeNode = FocusScope.of(context)
拿到句柄后,可以使用下面代码来获取焦点:
focusScopeNode.requestFocus(focusNode);
其中 focucsNode 是为 TextField 创建的 FocusNode, 这个操作可以让该 TextField 获取焦点。 调用 focusNode.unfocus() 可以取消焦点。
2.5.1.5 监听焦点状态改变事件
通过 FocusNode 可以监听焦点改变的事件:
focusNode.addListener((){ print(focusNode.hasFocus);})
true为获取焦点,false为失去焦点
2.5.2 表单
表单Form 对输入框进行分组和统一操作。 就像 Android 的原生组件 RadioGroup 之于 RadioButton 一样, Form 可以管理内容校验、输入框重置等。
Form 继承自 StatefulWidget,其状态管理在 FormState 里面,来看看 From 的定义:
class Form extends StatefulWidget { const Form({ Key? key, required this.child, @Deprecated( 'Use autovalidateMode parameter which provides more specific ' 'behavior related to auto validation. ' 'This feature was deprecated after v1.19.0.', ) this.autovalidate = false, this.onWillPop, this.onChanged, AutovalidateMode? autovalidateMode, }) ...
autovalidate 是否自动校验输入内容,当为true时,每一个 FormField 内容发生变化时都会校验合法性,并直接显示错误信息,否则就需要通过调用 FormState.validate() 来手动校验 v1.19 已经废弃了,改成使用 AutovalidateModeautovalidateMode 自动校验模式,是上面的替换,它有三个枚举值: ①disable:当 FormField 内容改变时不做校验 ②always:即使用户没有用户交互也要校验合法性 ③onUserInteraction:只有在用户交互时才会去校验合法性onWillPop 决定 Form 所在的路由是否可以直接返回。该回调返回一个 Future 对象,如果 Future 的最终结果是 false,则当前路由不会返回,如果为 true,则会返回到上一个路由。 这个属性通常是用于拦截返回按钮的onChanged Form 的任意一个 FormField 内容发生改变时就会调用该方法
2.5.2.1 FormField
Form 的子孙元素是 FormField 类型,FormField 是一个抽象类,定义了几个属性, FormState 内部通过他们来完成操作, FormField 部分定义如下:
const FormField({ Key? key, required this.builder, this.onSaved, this.validator, this.initialValue, @Deprecated( 'Use autovalidateMode parameter which provides more specific ' 'behavior related to auto validation. ' 'This feature was deprecated after v1.19.0.', ) this.autovalidate = false, this.enabled = true, AutovalidateMode? autovalidateMode, this.restorationId, })
onSaved 保存时的回调validator 验证合法性的回调initValue 初始值
为了方便使用, Flutter 提供了一个 TextFormFild 组件,继承自 FormField 类,还包装了 TextFileld ,可以直接当成 Form 的 FormField 来使用, 相当于用 Form 来管理 TextField
2.5.2.2 FormState
Form 表单的状态类就是 FormState, 可以通过 Form.of 或者 GlobalKey 获得,通过获得它来对 Form 的子孙 FormField 进行统一操作。
FormState 常用的三个方法:
FormState.validate():调用此方法后, 会调用Form 子孙FormField.validate() 回调,如果有一个检验失败,那么会返回 false,这样所有校验失败的 Widget 都会给出错误提示FormState.save():调用此方法后,会调用 子孙的FormFild.save() 回调,用于保存表单内容FormState.reset(): 会将子孙 FormField 的内容清空
2.5.2.3 示例
用户名不能为空,如果为空则提示“用户名不能为空”密码不能小于6位,如果小于6位则提示 “密码不能少于6位”
代码如下:
import 'package:flutter/material.dart';class FormTestRoute extends StatefulWidget { const FormTestRoute({Key? key}) : super(key: key); @override State
效果如下图所示:
参考文章
官方学习文档Basics Widgets
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~