Flutter 中的 widget
当 State 被改变时,可以手动调用其 setState()方法通知 Flutter framework 状态发生改变,Flutter framework 在收到消息后,会重新调用其 build 方法重新构建 widget 树,从而达到更新 UI 的目的。
class StatefulState extends State<StatefulApp>{int _i;///当 Widget 第一次插入到 Widget 树时会被调用,对于每一个 State 对象,Flutter framework 只会调用一次该回调 @overridevoid initState() {
super.initState();_i= 1;
}@overrideWidget build (BuildContext context) {return MaterialApp (title: "Widget 演示",theme: ThemeData(),home:Scaffold (appBar: AppBar (title: Text("Widget")),body: RaisedButton (onPressed: () {
//修改状态,setState 会重新调用 build 更新 uisetState(() {_i++;});},child: Text("Hello,Flutter! $_i"),),));}}
State 生命周期
State 的生命周期为:
State 类除了 build 之外还提供了很多方法能够让我们重写,这些方法会在不同的状态下由 Flutter 调起执行,所以这些方法我们就称之为生命周期方法。在这里我们用 statefulwidget 点击按钮后移除子 statefulwidget。
import 'package:flutter/material.dart';void main () => runApp(MyApp());class MyApp extends StatefulWidget {@override_MyAppState createState() => _MyAppState();}class _MyAppState extends State<MyApp> {bool isShowChild;
///当 Widget 第一次插入到 Widget 树时会被调用,对于每一个 State 对象,Flutter framework 只会调用一次该回调 @overridevoid initState() {super.initState();isShowChild = true;debugPrint("parent initState......");
}
///初始化时,在 initState()之后立刻调用
///当依赖的 InheritedWidget rebuild,会触发此接口被调用
@overridevoid didChangeDependencies() {
super.didChangeDependencies();debugPrint("parent didChangeDependencies......");
}///绘制界面,当 setState 触发的时候会再次被调用
@overrideWidget build(BuildContext context) {debugPrint("parent build......");
return MaterialApp(home: Scaffold(
body: Center(child: RaisedButton(onPressed: () {setState(() {isShowChild = !isShowChild;
});
},child: isShowChild ? Child() : Text("演示移除 Child"),
)),
),);
}
///状态改变的时候会调用该方法,比如调用了 setState
@overridevoid didUpdateWidget(MyApp oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("parent didUpdateWidget......");
}
///当 State 对象从树中被移除时,会调用此回调
@override
void deactivate() {super.deactivate();debugPrint('parent deactivate......');
}
///当 State 对象从树中被永久移除时调用;通常在此回调中释放资源
@override
void dispose() {
super.dispose();debugPrint('parent dispose......');
}}class Child extends StatefulWidget {
@override_ChildState createState() => _ChildState();}class _ChildState extends State<Child> {
@override
Widget build(BuildContext context) {debugPrint("child build......");
return Tex
t('lifeCycle');
}
@overridevoid initState() {
super.initState();debugPrint("child initState......");
}
///初始化时,在 initState()之后立刻调用
///当依赖的 InheritedWidget rebuild,会触发此接口被调用
@override
void didChangeDependencies() {
super.didChangeDependencies();debugPrint("child didChangeDependencies......");
}///父 widget 状态改变的时候会调用该方法,比如父节点调用了 setState
@overridevoid didUpdateWidget(Child oldWidget) {super.didUpdateWidget(oldWidget);debugPrint("child didUpdateWidget......");
}
///当 State 对象从树中被移除时,会调用此回调
@overridevoid deactivate() {
super.deactivate();debugPrint('child deactivate......');
}
///当 State 对象从树中被永久移除时调用;通常在此回调中释放资源
@overridevoid dispose() {
super.dispose();debugPrint('child dispose......');
}}
执行的输出结果显示为:
运行到显示
I/flutter (22218): parent initState......I/flutter (22218): parent didChangeDependencies......I/flutter (22218): parent build......I/flutter (22218): child initState......I/flutter (22218): child didChangeDependencies......I/flutter (22218): child build......
点击按钮会移除 Child
I/flutter (22218): parent build......I/flutter (22218): child deactivate......I/flutter (22218): child dispose......
将 MyApp 的代码由 child:isShowChild?Child():Text("演示移除 Child"),改为 child:Child(),点击按钮时
I/flutter (22765): parent build......I/flutter (22765): child didUpdateWidget......I/flutter (22765): child build......
基础 widget
文本显示
Text
Text 是展示单一格式的文本 Widget(Android TextView)。
import 'package:flutter/material.dart';/// main 方法 调用 runApp 传递 Widget,这个 Widget 成为 widget 树的根 void main() => runApp(TextApp());/// 1、单一文本 Text//创建一个无状态的 Widgetclass TextApp extendsStatelessWidget {
@overrideWidget build(BuildContext context) {
//封装了应用程序实现 Material Design 所需要的一些 widgetreturn MaterialApp(title: "Text 演示",//标题,显示在 recent 时候的标题
//主页面
//Scaffold : Material Design 布局结构的基本实现。home: Scaffold(
//ToolBar/ActionBarappBar: AppBar(title: Text("Text")),body: Text("Hello,Flutter"),
),
);
}}
在使用 Text 显示文字时候,可能需要对文字设置各种不同的样式,类似 Android 的 android:textColor/Size 等
在 Flutter 中也拥有类似的属性
Widget _TextBody() {
return Text("Hello,Flutter",style: TextStyle(
//颜色 color: Colors.red,
//字号 默认 14fontSize: 18,
//粗细 fontWeight: FontWeight.w800,
//斜体 fontStyle: FontStyle.italic,
//underline:下划线,overline:上划线,lineThrough:删除线 decoration: TextDecoration.lineThrough,decorationColor: Colors.black,
//solid:实线,double:双线,dotted:点虚线,dashed:横虚线,wavy:波浪线 decorationStyle:TextDecorationStyle.wavy),
);}class TextApp extends StatelessWidget {
@overrideWidgetbuild(BuildContext context){
return MaterialApp(title: "Text 演示",home: Scaffold(appBar: AppBar(title: Text("Text")),body: _TextBody(),
),
);
}}
RichText
如果需要显示更为丰富样式的文本(比如一段文本中文字不同颜色),可以使用 RichText 或者 Text.rich
Widget _RichTextBody() {
var textSpan = TextSpan(text: "Hello",style: TextStyle(color: Colors.red),children: [TextSpan(text: "Flu", style: TextStyle(color: Colors.blue)),TextSpan(text: "uter", style: TextStyle(color: Colors.yellow)),],
);//Text.rich(textSpan);return RichText(text: textSpan);}
DefaultTextStyle 在 widget 树中,文本的样式默认是可以被继承的,因此,如果在 widget 树的某一个节点处设置一个默认的文本样式,那么该节点的子树中所有文本都会默认使用这个样式。相当于在 Android 中定义 Theme
Widget _DefaultStyle(){DefaultTextStyle(
//设置文本默认样式 style: TextStyle(color:Colors.red,fontSize: 20.0,
),textAlign: TextAlign.start,child: Column(crossAxisAlignment:CrossAxisAlignment.start,children: <Widget>[
Text("Hello Flutter!"),
Text("Hello Flutter!"),
Text("Hello Flutter!",style: TextStyle(inherit: false,//不继承默认样式 color: Colors.grey),
),
],
),
);}
FlutterLogo 这个 Widget 用于显示 Flutter 的 logo......
Widget flutterLogo() {
return FlutterLogo(
//大小 size: 100,
//logo 颜色 默认为 Colors.bluecolors: Colors.red,//markOnly:只显示 logo,horizontal:logo 右边显示 flutter 文字,stacked:logo 下面显示文字 style: FlutterLogoStyle.stacked,
//logo 上文字颜色 textColor: Colors.blue,
);}
Icon
主要用于显示内置图标的 Widget
Widget icon() {
return Icon(
//使用预定义 Material icons
// https://docs.flutter.io/flutter/material/Icons-class.html
Icons.add,size: 100,color: Colors.red);}
Image 显示图片的 Widget。图片常用的格式主要有 bmp,jpg,png,gif,webp 等,Android 中并不是天生支持 gif 和 webp 动图,但是这一特性在 flutter 中被很好的支持了。
Iamge.asset 在工程目录下创建目录,如:assets,将图片放入此目录。打开项目根目录:pubspec.yaml
return MaterialApp(title: "Image 演示",home: Scaffold(appBar: AppBar(title: Text("Image")),body: Image.asset("assets/banner.jpeg"),
),);
Image.file 在 sd 卡中放入一张图片。然后利用 path_provider 库获取 sd 卡根目录(Dart 库版本可以在:https://pub.dartlang.org/packages查询)。
注意权限
class ImageState extends State<ImageApp> {
Image image;
@overridevoid initState() {
super.initState();getExternalStorageDirectory().then((path) {setState(() {image = Image.file(File("{Platform.pathSeparator}banner.jpeg"));});});
}
@override
Widget build(BuildContext context) {
return MaterialApp(title: "Image 演示",home: Scaffold(appBar: AppBar(title: Text("Image")),body: image,
),
);
}}
Image.network
直接给网络地址即可。Flutter 1.0,加载 https 时候经常出现证书错误。必须断开 AS 打开 app
Image.memory
Future<List<int>> _imageByte() async {
String path = (await getExternalStorageDirectory()).path;
return await File("{Platform.pathSeparator}banner.jpeg").readAsBytes();}class ImageState extends State<ImageApp> {
Image image;
@overridevoid initState() {
super.initState();_imageByte().then((bytes) {setState(() {image = Image.memory(bytes);});});
}
@override
Widget build(BuildContext context) {return MaterialApp(title: "Image 演示",home: Scaffold(appBar: AppBar(title: Text("Image")),body: image,
),);}}
CircleAvatar
CircleAvatar(
//图片提供者 ImageProviderbackgroundImage: AssetImage("assets/banner.jpeg"),
//半径,控制大小 radius: 50.0,
);
FadeInImage 当使用默认 Image widget 显示图片时,您可能会注意到它们在加载完成后会直接显示到屏幕上。这可能会让用户产生视觉突兀。如果最初显示一个占位符,然后在图像加载完显示时淡入,我们可以使用 FadeInImage 来达到这个目的!
image = FadeInImage.memoryNetwork(placeholder: kTransparentImage,image: 'https://flutter.io/images/homepage/header-illustration.png',
);
按钮
Material widget 库中提供了多种按钮 Widget 如 RaisedButton、FlatButton、OutlineButton 等,它们都是直接或间接对 RawMaterialButton 的包装定制,所以他们大多数属性都和 RawMaterialButton 一样。所有 Material 库中的按钮都有如下相同点:
按下时都会有“水波动画”。
有一个 onPressed 属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。
RaisedButton"漂浮"按钮,它默认带有阴影和灰色背景
RaisedButton(child: Text("normal"),onPressed: () => {},
)
FlatButton
扁平按钮,默认背景透明并不带阴影
FlatButton(child: Text("normal"),onPressed: () => {},
)
OutlineButton
默认有一个边框,不带阴影且背景透明。
OutlineButton(child: Text("normal"),onPressed: () => {},
)
IconButton
可点击的 Icon
IconButton(child: Text("normal"),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,//按钮的内容})FlatButton( onPressed: () => {},child: Text("Raised"),
//蓝色 color: Colors.blue,
//水波 splashColor: Colors.yellow,
//深色主题,这样文字颜色会变成白色 colorBrightness: Brightness.dark,
//圆角按钮 shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)
),)
而 RaisedButton,默认配置有阴影,因此在配置 RaisedButton 时,拥有一系列 elevation 属性的配置
const RaisedButton({
...
this.elevation = 2.0,//正常状态下的阴影 this.highlightElevation = 8.0,//按下时的阴影 this.disabledElevation = 0.0,// 禁用时的阴影...}
输入框
import 'package:flutter/material.dart';void main() => runApp(Demo1());class Demo1 extends StatelessWidget {
@overrideWidget build(BuildContext context) {return MaterialApp(title: "Demo1",home: Scaffold(appBar: AppBar(title: Text("登录"),
),//线性布局,垂直方向 body: Column(children: <Widget>[
TextField(
//自动获得焦点 autofocus: true,decoration: InputDecoration(labelText: "用户名",hintText: "用户名或邮箱",prefixIcon: Icon(Icons.person)),),TextField(
评论