UI层

Flutter Widget组件的概念受到React.js框架的启发。核心思想是通过Widget构建UI层。

Widget简介

Widget用于绘制UI层,最基础的Flutter App调用runApp()函数。

  1. import 'package:flutter/material.dart';
  2. void main() {
  3. runApp(
  4. Center(
  5. child: Text(
  6. 'Hello, world!',
  7. textDirection: TextDirection.ltr,
  8. ),
  9. ),
  10. );
  11. }

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 的状态对象。

  1. class Counter extends StatefulWidget {
  2. // This class is the configuration for the state. It holds the
  3. // values (in this case nothing) provided by the parent and used by the build
  4. // method of the State. Fields in a Widget subclass are always marked "final".
  5. @override
  6. _CounterState createState() => _CounterState();
  7. }
  8. class _CounterState extends State<Counter> {
  9. int _counter = 0;
  10. void _increment() {
  11. setState(() {
  12. // This call to setState tells the Flutter framework that
  13. // something has changed in this State, which causes it to rerun
  14. // the build method below so that the display can reflect the
  15. // updated values. If you change _counter without calling
  16. // setState(), then the build method won't be called again,
  17. // and so nothing would appear to happen.
  18. _counter++;
  19. });
  20. }
  21. @override
  22. Widget build(BuildContext context) {
  23. // This method is rerun every time setState is called, for instance
  24. // as done by the _increment method above.
  25. // The Flutter framework has been optimized to make rerunning
  26. // build methods fast, so that you can just rebuild anything that
  27. // needs updating rather than having to individually change
  28. // instances of widgets.
  29. return Row(
  30. children: <Widget>[
  31. RaisedButton(
  32. onPressed: _increment,
  33. child: Text('Increment'),
  34. ),
  35. Text('Count: $_counter'),
  36. ],
  37. );
  38. }
  39. }

你可能好奇,为什么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布局组件

  • Center
  • Container

    Multi-child布局组件

  • Row

  • Column
  • ListView
  • Stack

Material应用程序

采用Material Design设计标准实现的Material library,Flutter允许使用Scaffold Widget组件。它提供了默认的Banner、背景色,并提供了drawers、sanck bars及底部菜单等组件。

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return MaterialApp(
  5. title: 'Flutter layout demo',
  6. home: Scaffold(
  7. appBar: AppBar(
  8. title: Text('Flutter layout demo'),
  9. ),
  10. body: Center(
  11. child: Text('Hello World'),
  12. ),
  13. ),
  14. );
  15. }
  16. }

No-material应用程序

默认的No-material App不包含AppBar,title及背景颜色。如果需要在non-material app中创建这些特性,需要自己创建。

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return Container(
  5. decoration: BoxDecoration(color: Colors.white),
  6. child: Center(
  7. child: Text(
  8. 'Hello World',
  9. textDirection: TextDirection.ltr,
  10. style: TextStyle(
  11. fontSize: 32,
  12. color: Colors.black87,
  13. ),
  14. ),
  15. ),
  16. );
  17. }
  18. }

尺寸Widget

当布局尺寸太大,无法适应设备时,黄黑相间的条纹将会显现在设备上。为了解决这个问题,可以通过使用Expended 组件。它能使组件在Row或Column的纬度适应设备尺寸。

通用布局组件(Common layout widget)

标准组件

  • Container:可以为Widget添加padding、margin、边框、背景色或其他装饰

image.png

  • GridView:组件可显示为一个可滑动的grid
  • ListView:组件可显示为一个可滑动的list
  • Stack:可以在一个组件上覆盖其他组件

    Material组件

  • Card

  • ListTitle