2019-06-01 27 Flutter
Widget
runApp
函数接受Widget
, 并使其成为Widget的根
void main() {
runApp(
...
);
}
-
StatelessWidget
, 例如Icon
、Text
等无状态Widget
, 需要复写Widget#build()
函数 -
StatefulWidget
, 与用户交互或随时间变化, 当Widget
改变时, 调用setState()
通知框架重绘widget
, 自定义StatefulWidget
需要创建StatefulWidget
和State
类
// 实例,
class FavoriteWidget extends StatefulWidget {
@override
createState() => new _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
...
void _toggleFavorite() {
// 通知刷新
setState(() {
if (_isFavorite) {
_isFavorite = false;
_favoriteCount -= 1;
} else {
_favoriteCount += 1;
_isFavorite = true;
}
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Container(
padding: new EdgeInsets.all(0.0),
child: new IconButton(
icon: _isFavorite
? new Icon(Icons.star)
: new Icon(Icons.star_border),
color: Colors.red[500],
onPressed: _toggleFavorite),
),
new SizedBox(
width: 18.0,
child: new Container(
child: new Text('$_favoriteCount'),
),
),
],
);
}
}
- 管理状态
Widget
管理自己的状态, 在手势(事件响应)中,Widget
在类中响应(setState()
)刷新UI- 父
Widget
管理Widget
状态, 在手势(事件响应)中, 需要父Widget
更新, 则把状态由父Widget
管理, 子Widget
把事件回调给父Widget
- 混搭管理, 父
Widget
和子Widget
共同响应刷新UI
布局
- 行(
Row
)水平排布, 列(Column
)垂直排布, 包含mainAxisAlignment
主轴和crossAxisAligment
交叉轴对齐属性, 类似Android的LinearLayout
-
ExpandWidget
控制沿主轴方向的widget
大小, 通过调整ExpandWidget#flex
属性,默认是1, 类似CSS的flex - 拥有单子元素的布局widget
Container
, 绘制、定位、调整大小Container( constraints: BoxConstraints.expand( height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0, ), padding: const EdgeInsets.all(8.0), color: Colors.blue[600], alignment: Alignment.center, child: Text('Hello World', style: Theme.of(context) .textTheme .display1 .copyWith(color: Colors.white)), transform: Matrix4.rotationZ(0.1), )
Padding
, 给子widget添加指定填充Padding( padding: EdgeInsets.all(8.0), child: const Card(child: Text('Hello World!')), )
Center
, 将子widget居中显示Align
, 将子widget对齐
Align(
alignment: Alignment(0.2, 0.6),
child: FlutterLogo(
size: 60,
)
)
ConstrainedBox
约束布局ConstrainedBox( constraints: const BoxConstraints.expand(), child: const Card(child: Text('Hello World!')), )
- 多个子元素的布局
- 常用的如
Row
,Column
Stack
允许子widget堆叠Stack( children: <Widget>[ Container( width: 100, height: 100, color: Colors.red, ), Container( width: 90, height: 90, color: Colors.green, ), ... ], )
ListView
, 滚动列表布局ListView( padding: const EdgeInsets.all(8.0), children: <Widget>[ Container( height: 50, color: Colors.amber[600], child: const Center(child: Text('Entry A')), ), Container( height: 50, color: Colors.amber[500], child: const Center(child: Text('Entry B')), ), ... ], )
- 常用的如
手势
Pointers
, 表示touch, stylus, 或者mouse事件PointerDownEvent
, The pointer has made contact with the device.PointerMoveEvent
, The pointer has moved with respect to the device while the pointer is in contact with the device.PointerUpEvent
, The pointer has stopped making contact with the device.PointerCancelEvent
, The input from the pointer is no longer directed towards this receiver.
GestureDetector
, 拦截事件的widget
GestureDetector(
onTap: () {
setState(() { _lights = true; });
},
child: Container(
color: Colors.yellow,
child: Text('TURN LIGHTS ON'),
),
)
动画
- 补间(Tween)动画
- 基于物理的动画
Http网络请求
import 'dart:convert';
import 'dart:io';
_getIPAddress() async {
var url = 'https://httpbin.org/ip';
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(url));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var json = await response.transform(utf8.decoder).join();
var data = jsonDecode(json);
String result = data['origin'];
}
...
}