UI层
Flutter Widget组件的概念受到React.js框架的启发。核心思想是通过Widget构建UI层。
Widget简介
Widget用于绘制UI层,最基础的Flutter App调用runApp()
函数。
import 'package:flutter/material.dart';
void main() {
runApp(
Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
runApp()
函数取得 Widget
并把它做为 Widget tree
的根节点。
基础组件(Basic Widget)
Text
Row, Column
基于Web的flexbox布局模型,用于创建在水平(Row)和垂直(Column)方向上的灵活布局。
Stack
不同于线性方向(水平或垂直)布局,Stack允许按照绘制顺序将Widget堆叠在一起,然后可以在Stack组件内部使用基于Positioned的自组件,分别相对于外层Stack组件的上、右、下、左边距进行定位。Stack相当于Web页面的绝对定位布局方式。
Container
Container允许创建矩形可视元素。Container可以使用BoxDecoration进行装饰,如:背景、边框或阴影。Container也可以包括 margins、padding及可以应用在其上的尺寸约束条件。另外,Container可以使用matrix在三维空间中进行变换。
手势控制
详细内容参考:GestureDetector
StatelessWidget 和 StatefulWidget
StatelessWidget和StatefulWidget的区别在于Widget是否管理状态。
StatelessWidget从它的父组件获取参数,并将他们保存在 final
成员变量中。
为构建更复杂的体验,例如:以更有趣的方式对用户输入作出反应,应用程序通常带有一些状态。Flutter使用StatefulWidget来实现这个想法。StatefulWidget 是特殊的 Widget,它知道如何生成保持 state 的状态对象。
class Counter extends StatefulWidget {
// This class is the configuration for the state. It holds the
// values (in this case nothing) provided by the parent and used by the build
// method of the State. Fields in a Widget subclass are always marked "final".
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _counter = 0;
void _increment() {
setState(() {
// This call to setState tells the Flutter framework that
// something has changed in this State, which causes it to rerun
// the build method below so that the display can reflect the
// updated values. If you change _counter without calling
// setState(), then the build method won't be called again,
// and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance
// as done by the _increment method above.
// The Flutter framework has been optimized to make rerunning
// build methods fast, so that you can just rebuild anything that
// needs updating rather than having to individually change
// instances of widgets.
return Row(
children: <Widget>[
RaisedButton(
onPressed: _increment,
child: Text('Increment'),
),
Text('Count: $_counter'),
],
);
}
}
你可能好奇,为什么StatefulWidget和State是两个分开的对象。在Flutter中,这两种类型的对象有不同的生命周期。Widgets 是临时对象,用于在当前状态下构建应用程序的展示。而状态对象从另一个角度讲,在 build() 函数被调用之前,用于保存信息。
在Fultter中,Widget 要么是stateful的,要么是stateless的。如果Widget可以根据用户交互行为发生改变,那么它肯定是 stateful的。组件的state被存储在 State 对象中,将widget的状态和显示分隔开。state包含了可以被修改的值,当widget的状态需要被改变是,state对象调用 setState() 方法通知flutter框架重绘组件。
创建Stateful组件
要点:
- 一个Stateful组件实现了两个类:
- StatefuleWidget子类
- State子类
- state类包含了组件的可变更状态和组件的
build()
方法。
管理Widget状态
- 管理状态的方式有多种
- 作为组件的设计者,可以选择不同的状态管理方法
- Widget管理自己的状态
- 父组件管理组件状态
- 采用 mix-and-match 方法管理状态
- 如果有疑问,请先从父组件管理状态开始
状态管理的几种方式
如果决定用什么方式来管理状态呢?Flutter官方给出了一些原则性建议。
- 如果 state 是用户数据,例如:checkbox的状态是选中还是未选中,slider的位置等信息,最好的方式是由父组件去管理状态。
- 如果state是展示样式性的,例如:动画效果等,最好让组件自己去管理这些状态。
如果还有疑问,那么就用父组件去管理状态吧。
Flutter 中的布局
Widget是可以构建UI的类
Widget可以做为布局和UI元素使用
可以通过组合简单Widget使其成为复杂Widget
分类布局组件(Layout Widget)
https://flutter.dev/docs/development/ui/widgets/layout
Single-child布局组件
Material应用程序
采用Material Design设计标准实现的Material library,Flutter允许使用Scaffold Widget组件。它提供了默认的Banner、背景色,并提供了drawers、sanck bars及底部菜单等组件。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter layout demo'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}
No-material应用程序
默认的No-material App不包含AppBar,title及背景颜色。如果需要在non-material app中创建这些特性,需要自己创建。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}
尺寸Widget
当布局尺寸太大,无法适应设备时,黄黑相间的条纹将会显现在设备上。为了解决这个问题,可以通过使用Expended 组件。它能使组件在Row或Column的纬度适应设备尺寸。
通用布局组件(Common layout widget)
标准组件
- Container:可以为Widget添加padding、margin、边框、背景色或其他装饰