Flutter中文网:https://book.flutterchina.club/chapter3/flutter_widget_intro.html
Flutter第三方库:https://pub.flutter-io.cn/packages
Widget:Flutter中几乎所有对象都是一个Widget,不仅可以表示UI元素,也可以表示一些功能性组件如(手势检测GestureDetector)、应用主题数据传递的Theme等等。
Element:Flutter中真正代表屏幕上显示的元素是Element,也就是说Widget只是描述Element的一个配置;
在Flutter我们通常会通过继承StatelessWidget和StatefulWidget来间接继承Widget类来实现,而StatelessWidget和StatefulWidget都是直接继承Widget。
StatelessWidget:用于不需要维护状态的场景;(重写createElement())
StatefulWidget:用于有状态需要改变的场景;(重写了createElement()),返回的Element对象和StatelessWidget返回的不相同,另外StatefulWdiget类中添加了一个新的接口createState();
State
一个StatefulWidget类会对应一个State类,State表示与对应的StatefulWidget要维护的状态;
State中保持状态的信息可以:
1、在widget build时可以被同步读取
2、在widget生命周期种可以改变,当State被改变时,可以手动调用起setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用起build方法重新构建widget树,从而达到更新UI的目的。
State生命周期:
initState:当Widget第一次插入 到Widget树时回被调用,对于每一个State对象,Flutter framework只会调用一次该回调;
didChangeDependencies:当State对象的依赖发生变化时会被调用;
build():用于构建Widget子树,会在如下场景调用:
1、在调用initState()之后;
2、在调用didUpdateWidget()之后;
3、在调用setState()之后;
4、在调用didChangeDependencies()之后;
5、在State对象从树中一个位置移除后(回调用deactivate)又重新插入到树的其他位置之后;
reassmble():此方法专门为了开发回调而提供的,在热重载的时候回被调用,此模式在Release模式下永远不会被调用;
didUpdateWidget():在Widget重新构建时;
deactivate():当State对象从树种移除时,会调用此回调;
dispose():当State对象从树中被永久移除时调用,通常在此方法中释放资源;
文本及样式
Text:文本
textAlign:文本对齐方式;
maxLines:指定文本显示的最大行数,默认情况下,文本自动折行;
overflow:指定截断方式,默认直接截断;
textScaleFactor:代表文本相对于当前字体大小的缩放因子,是调整字体大小的一个快捷方式;
TextStyle:指定文本显示样式
height:行高;
fontFamily:字体;
fontSize:字体大小;
TextSpan:同一文本内容用不同的样式就可以用TextSoan,代表文本的一个片段;
DefaultTextStyle:用于设置默认文本的样式(设置后 他下面的文本都通用);
按钮
RaisedButton:漂浮按钮,默认带有阴影和灰色背景,按下后,阴影后变大;
FlatButton:扁平按钮,默认背景透明并不带阴影,按下后会有背景色;
OutlineButton:默认一个边框,不带阴影且背景透明,按下后,边框颜色会变量,同时出现背景和阴影(较弱);
IconButton:图标button,不包括文字,点击后会出现背景;
自定义按钮外观
//列子
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, //按钮的内容
})
图片及ICON
Flutter中,Image的数据源可以是asset、文件、内存以及网络。
从asset中加载图片
1、在工程目录下创建一个images目录,存放图片
2、在pubspec.yml椎间盘买个的flutter添加
assets:
-images/图片名称.png
3、加载图片
Image(
image:AssetImage("images/图片.png"),
width:80.0,
)
//或者
Image.asset("images/图片.png",width:80.0)
从网络加载图片
Image(
image:NetWorkImage("网络图片地址"),
width:80.0
)
//或者
Image.network(
"网络图片地址",
width:80.0,
)
参数:
const Image({
...
this.width, //图片的宽
this.height, //图片高度
this.color, //图片的混合色值
this.colorBlendMode, //混合模式
this.fit,//缩放模式
this.alignment = Alignment.center, //对齐方式
this.repeat = ImageRepeat.noRepeat, //重复方式
...
})
//fit:该属性用于在图片的显示空间和图片本身大小不同时指定图片的适应模式,适应模式在BoxFit中定义了一个枚举
fill:会拉伸填充满显示空间,图片本身长宽比会发生变化,图片会变长;
cover:会按照图片的长宽比放大后居中填满显示空间,图片不会变形,超出显示空间的部分会被剪裁;
contain:默认适应规则,图片会在保证图片长宽比不变的情况下缩放以适应当前显示空间,图片不会变形;
fitWith:图片的宽度会缩放到显示的宽度,高度会按照比例缩放,然后居中显示,图片不会变形,超出显示的部分会被裁减;
fitHeight:图片的高度会缩放到显示空间的高度,宽度会按比例缩放,然后居中显示,图片不会变形,超出部分会被裁减;
none:图片没有适应策略,会在显示空间内显示图片,如果图片比显示空间大,则显示空间只会显示图片的中间部分;
单选开关和复选框
单选:Switch:
复选框:Checkbox:
输入框和表单
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<String> onChanged,
VoidCallback onEditingComplete,
ValueChanged<String> onSubmitted,
List<TextInputFormatter> inputFormatters,
bool enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
...
})
controller:编辑框控制器,通过它可以设置、获取编辑框的内容、选择编辑内容、监听内容文本改变事件;
focusNode:用于控制TextField是否占有当前键盘的输入焦点,它是我们和键盘交互的一个handle;
InputDecoration :用于控制文本的外观显示,如提示文本、背景颜色、边框等;
keyboardType:用于设置该输入框默认的键盘输入类型;(
枚举类型:
text:文本输入键盘;
multilinr:多行文本,需要maxLines配合使用;
number:数字键盘;
phone:优化后的电话输入键盘;
datetime:优化后日期数去键盘;
emailAddress:优化后电子邮箱地址;
url:优化后的url输入键盘
)
textInputAction:键盘回车图标;
style:正在编辑文本的样式;
textAlign:输入框内编辑文本在水平方向的对齐方式;
autofocus:是否自动获取焦点;
obscureText:是否隐藏正在编辑的文本;
maxLines:最大行数;
maxLength:输入框文本的最大长度;
maxLengthEnforced:输入框文本长度超过maxLength是否阻止输入;
onChange:输入框内容改变时的回调函数;
onEditingComplete和onSubmitted:这两个回调都是在输入框输入完成时触发
inputFormatters:用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验。
enable:如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)。
cursorWidth、cursorRadius和cursorColor:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。
获取输入框内容的两种方式
1、定义两个变量,用于保存用户名和密码,然后在onChange触发时,各自保存一下输入内容。
2、
//定义一个controller
TextEditingController _unameController=new TextEditingController();
//然后设置输入框controller:
TextField(
autofocus: true,
controller: _unameController, //设置controller
...
)
//通过controller获取输入框内容
print(_unameController.text)
监听文本变化
//设置onChange回调,如:
TextField(
autofocus: true,
onChanged: (v) {
print("onChange: $v");
}
)
//通过controller监听,如:
@override
void initState() {
//监听输入改变
_unameController.addListener((){
print(_unameController.text);
});
}
Form
继承自StatefulWidget对象,它对应的状态类为FromState;
- autovalidate:是否自动校验输入内容;当为
true
时,每一个子FormField内容发生变化时都会自动校验合法性,并直接显示错误信息。否则,需要通过调用FormState.validate()
来手动校验。
- onWillPop:决定Form所在的路由是否可以直接返回(如点击返回按钮),该回调返回一个
Future
对象,如果Future的最终结果是false,则当前路由不会返回;如果为true
,则会返回到上一个路由。此属性通常用于拦截返回按钮。 - onChanged:Form的任意一个子FormField内容发生变化时会触发此回调。
FormField:
Form的子孙元素必须是FormField类型,FormField是一个抽象类,定义几个属性,FormState内部通过它们来完成操作,FormField部分定义如下:
const FormField({
...
FormFieldSetter<T> onSaved, //保存回调
FormFieldValidator<T> validator, //验证回调
T initialValue, //初始值
bool autovalidate = false, //是否自动校验。
})
为了方便使用,Flutter提供了一个TextFormField widget,它继承自FormField类,也是TextField的一个包装类,所以除了FormField定义的属性之外,它还包括TextField的属性。
FormState:
FormState为Form的State类,可以通过Form.of()
或GlobalKey获得。我们可以通过它来对Form的子孙FormField进行统一操作。我们看看其常用的三个方法:
FormState.validate()
:调用此方法后,会调用Form子孙FormField的validate回调,如果有一个校验失败,则返回false,所有校验失败项都会返回用户返回的错误提示。FormState.save()
:调用此方法后,会调用Form子孙FormField的save回调,用于保存表单内容FormState.reset()
:调用此方法后,会将子孙FormField的内容清空。
class _FormTestRouteState extends State<FormTestRoute> {
TextEditingController _unameController = new TextEditingController();
TextEditingController _pwdController = new TextEditingController();
GlobalKey _formKey= new GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return PageScaffold(
title: "Form Test",
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
child: Form(
key: _formKey, //设置globalKey,用于后面获取FormState
autovalidate: true, //开启自动校验
child: Column(
children: <Widget>[
TextFormField(
autofocus: true,
controller: _unameController,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
icon: Icon(Icons.person)
),
// 校验用户名
validator: (v) {
return v
.trim()
.length > 0 ? null : "用户名不能为空";
}
),
TextFormField(
controller: _pwdController,
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
icon: Icon(Icons.lock)
),
obscureText: true,
//校验密码
validator: (v) {
return v
.trim()
.length > 5 ? null : "密码不能少于6位";
}
),
// 登录按钮
Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
padding: EdgeInsets.all(15.0),
child: Text("登录"),
color: Theme
.of(context)
.primaryColor,
textColor: Colors.white,
onPressed: () {
//在这里不能通过此方式获取FormState,context不对
//print(Form.of(context));
// 通过_formKey.currentState 获取FormState后,
// 调用validate()方法校验用户名密码是否合法,校验
// 通过后再提交数据。
if((_formKey.currentState as FormState).validate()){
//验证通过提交数据
}
},
),
),
],
),
)
],
),
),
),
);
}
}