在前面搭好环境后以及快速了解的dart的语法后,开始学习Flutter的基础Widget!!
目录
Flutter Widget库介绍
Widget
StatelessWidget
StatefulWidget
State
State生命周期
Text
使用字体
在asset中声明
使用字体
Package中的字体
按钮
自定义按钮外观
图片
ImageProvider
从asset中加载图片
从网络加载图片
TextField
在Flutter中大部分类皆继承Widget,Widget的功能是“描述一个UI元素的配置数据”,它就是说,Widget其实并不是表示最终绘制在设备屏幕上的显示元素,而只是显示元素的一个配置数据。实际上,Flutter中真正代表屏幕上显示元素的类是Element
,也就是说Widget只是描述Element
的一个配置。
Flutter提供了一套丰富、强大的基础widget,在基础widget库之上Flutter又提供了一套Material风格(Android默认的视觉风格)和一套Cupertino风格(iOS视觉风格)的widget库。要使用基础widget库,需要先导入:
// Android
import 'package:flutter/widgets.dart';
// iOS
import 'package:flutter/cupertino.dart';
下面是Widget类的源代码:
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
final Key key;
@protected
Element createElement();
@override
String toStringShort() {
return key == null ? '$runtimeType' : '$runtimeType-$key';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
StatelessWidget用于不需要维护状态的场景,它通常在build
方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => new StatefulElement(this);
@protected
State createState();
}
StatefulElement
间接继承自Element
类,与StatefulWidget相对应(作为其配置数据)。StatefulElement
中可能会多次调用createState()
来创建状态(State)对象。
createState()
用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用。例如,当一个Stateful widget同时插入到widget树的多个位置时,Flutter framework就会调用该方法为每一个位置生成一个独立的State实例,其实,本质上就是一个StatefulElement
对应一个State实例。
一个StatefulWidget类会对应一个State类,State表示与其对应的StatefulWidget要维护的状态,State中的保存的状态信息可以:
setState()
方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build
方法重新构建widget树,从而达到更新UI的目的 // 初始化状态,只执行一次
void initState() { }
// 当widget依赖的对象发生变化时调用,例如全局的主题或语言
void didChangeDependencies() { }
// 当widget重新构建时调用,根据canUpdate方法判断
void didUpdateWidget(covariant T oldWidget) { }
// 构建UI
void build() { }
// 调试模式下,热重载执行,Release模式不会执行
void reassemble() { }
// 当widget被移除时调用
void deactivate() { }
// 当widget被永久移除时,可以做释放资源
void dispose() { }
widget被加载显示的时候会依次调用initState,didChangeDependencies,build等方法。
点击热重载时会依次调用reassemble,didUpdateWidget,build等方法。
发生界面切换时会依次调用deactivate,dispose等方法。
显示文本,其一些样式属性和Android的TextView类似,比如,文本对齐方式,大小,颜色等等。
在Flutter中使用字体分两步完成。首先在pubspec.yaml
中声明它们,以确保它们会打包到应用程序中。然后通过TextStyle
属性使用字体。
要将字体打文件打包到应用中,和使用其它资源一样,要先在pubspec.yaml
中声明它。然后将字体文件复制到在pubspec.yaml
中指定的位置。如
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: assets/fonts/Raleway-Medium.ttf
weight: 500
- asset: assets/fonts/Raleway-SemiBold.ttf
weight: 600
- family: AbrilFatface
fonts:
- asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf
// 声明文本样式
const textStyle = const TextStyle(
fontFamily: 'Raleway',
);
// 使用文本样式
var buttonText = const Text(
"Use the font for this text",
style: textStyle,
);
要使用Package中定义的字体,必须提供package
参数。例如,假设上面的字体声明位于my_package
包中。然后创建TextStyle的过程如下
const textStyle = const TextStyle(
fontFamily: 'Raleway',
package: 'my_package', //指定包名
);
如果在package包内部使用它自己定义的字体,也应该在创建文本样式时指定package
参数,如上例所示。
一个包也可以只提供字体文件而不需要在pubspec.yaml中声明。 这些文件应该存放在包的lib/
文件夹中。字体文件不会自动绑定到应用程序中,应用程序可以在声明字体时有选择地使用这些字体。假设一个名为my_package的包中有一个字体文件:
lib/fonts/Raleway-Medium.ttf
然后,应用程序可以声明一个字体,如下面的示例所示:
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: packages/my_package/fonts/Raleway-Medium.ttf
weight: 500
lib/
是隐含的,所以它不应该包含在asset路径中。
在这种情况下,由于应用程序本地定义了字体,所以在创建TextStyle时可以不指定package
参数:
const textStyle = const TextStyle(
fontFamily: 'Raleway',
);
Material widget库中提供了多种按钮Widget如RaisedButton、FlatButton、OutlineButton等,它们都是直接或间接对RawMaterialButton的包装定制,所以他们大多数属性都和RawMaterialButton
一样。在介绍各个按钮时我们先介绍其默认外观,而按钮的外观大都可以通过属性来自定义,我们在后面统一介绍这些属性。另外,所有Material 库中的按钮都有如下相同点:
onPressed
属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。const FlatButton({
...
@required this.onPressed, //按钮点击回调
this.textColor, //按钮文字颜色
this.disabledTextColor, //按钮禁用时的文字颜色
this.color, //按钮背景颜色
this.disabledColor,//按钮禁用时的背景颜色
this.highlightColor, //按钮按下时的背景颜色
this.splashColor, //点击时,水波动画中水波的颜色
this.colorBrightness,//按钮主题,默认是浅色主题
this.padding, //按钮的填充
this.shape, //外形
@required this.child, //按钮的内容
})
Flutter中,我们可以通过Image来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络。
ImageProvider
是一个抽象类,主要定义了图片数据获取的接口load()
,从不同的数据源获取图片需要实现不同的ImageProvider
,如AssetImage
是实现了从Asset中加载图片的ImageProvider,而NetworkImage
实现了从网络加载图片的ImageProvider。
在工程根目录下创建一个images目录
,并将图片avatar.png拷贝到该目录。
在pubspec.yml
中的flutter
部分添加如下内容:
assets:
- images/avatar.png
加载图片
Image(
image: AssetImage("images/avatar.png"),
width: 100.0
);
Image也提供了一个快捷的构造函数Image.asset
用于从asset中加载、显示图片:
Image.asset("images/avatar.png",
width: 100.0,
)
Image(
image: NetworkImage(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
)
Image也提供了一个快捷的构造函数Image.network
用于从网络加载、显示图片:
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
)
TextField用于文本输入,它提供了很多属性。
const TextField({
...
TextEditingController controller,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType,
TextInputAction textInputAction,
TextStyle style,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool obscureText = false,
int maxLines = 1,
int maxLength,
bool maxLengthEnforced = true,
ValueChanged onChanged,
VoidCallback onEditingComplete,
ValueChanged onSubmitted,
List inputFormatters,
bool enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
...
})
controller:编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller来与文本框交互。如果没有提供controller,则TextField内部会自动创建一个。
focusNode:用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个handle。
InputDecoration:用于控制TextField的外观显示,如提示文本、背景颜色、边框等。
keyboardType:用于设置该输入框默认的键盘输入类型,取值如下:
| TextInputType枚举值 | 含义 | | ------------------- | --------------------------------------------------- | | text | 文本输入键盘 | | multiline | 多行文本,需和maxLines配合使用(设为null或大于1) | | number | 数字;会弹出数字键盘 | | phone | 优化后的电话号码输入键盘;会弹出数字键盘并显示"* #" | | datetime | 优化后的日期输入键盘;Android上会显示“: -” | | emailAddress | 优化后的电子邮件地址;会显示“@ .” | | url | 优化后的url输入键盘; 会显示“/ .” |
textInputAction:键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值,全部的取值列表读者可以查看API文档
null
,则无行数限制。ValueChanged
类型,它接收当前输入内容做为参数,而onEditingComplete不接收参数。false
,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)。
参考Flutter中文网