Flutter Widget

# 1. Widget

Flutter核心思想是用 widget 来构建你的 UI 界面。 Widget 描述了在当前的配置和状态下视图所应该呈现的样子。当 widget 的状态改变时,它会重新构建其描述(展示的 UI),框架则会对比前后变化的不同,以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。

在Flutter中,widget分为两类:Stateful(有状态)和 stateless(无状态)widget。

# 1.1 StatelessWidget

StatelessWidget没有内部状态,Icon、IconButton, 和Text都是无状态widget, 它们都是 StatelessWidget的子类。

# 1.2 StatefulWidget

StatefulWidget是动态的,用户可以和其交互(例如输入一个表单、 或者移动一个slider滑块),或者可以随时间改变 (也许是数据改变导致的UI更新)。Checkbox, Radio, Slider, InkWell, Form, and TextField 都是 stateful widgets, 它们都是 StatefulWidget的子类。

创建一个有状态的widget需要进行以下操作:

  • 要创建一个自定义有状态widget,需创建两个类:StatefulWidget和State。

  • 定义一个widget类,继承自StatefulWidget。

  • 子State,包含该widget状态并定义该widget build()方法的类,它继承自State。

  • 状态对象包含widget的状态和build() 方法。

  • 当widget的状态改变时,状态对象调用setState(),告诉框架重绘widget

# 2. Hello World

  • Demo Code
import "package:flutter/material.dart";

void main() {
  runApp(const HelloWorld());
}

class HelloWorld extends StatelessWidget {
  const HelloWorld({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text('ApeGeek'),
          ),
          body: const Center(
              child: Text(
            "Hello World !",
            style: TextStyle(fontSize: 22, color: Colors.red),
            overflow: TextOverflow.fade,
          ))),
    );
  }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • rendering

# 3. StatelessWidget

# 3.1 Text

Text widget 可以用来在应用内创建带样式的文本。

# 3.1.1 定义

const Text(
    String this.data, {
    Key? key,
    this.style,
    this.strutStyle,
    this.textAlign,
    this.textDirection,
    this.locale,
    this.softWrap,
    this.overflow,
    this.textScaleFactor,
    this.maxLines,
    this.semanticsLabel,
    this.textWidthBasis,
    this.textHeightBehavior,
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.2 Row

Row 是一个可以沿水平方向展示它的子组件的组件。

它还可以灵活布局,如果要让某个子组件填充满剩余剩余空间,请使用 Expanded 组件包裹该组件即可。

Row 组件是不可以滚动的,所以在 Row 组件中一般不会放置过多子组件,如果需要滚动的话应该考虑使用 ListView。

# 3.2.1 定义

Row({
    Key? key,
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
    MainAxisSize mainAxisSize = MainAxisSize.max,
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
    TextDirection? textDirection,
    VerticalDirection verticalDirection = VerticalDirection.down,
    TextBaseline? textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
    List<Widget> children = const <Widget>[],
  }) : super(
    children: children,
    key: key,
    direction: Axis.horizontal,
    mainAxisAlignment: mainAxisAlignment,
    mainAxisSize: mainAxisSize,
    crossAxisAlignment: crossAxisAlignment,
    textDirection: textDirection,
    verticalDirection: verticalDirection,
    textBaseline: textBaseline,
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3.2.2 常用属性

  • crossAxisAlignment:子组件沿着 Cross 轴(在 Row 中是纵轴)如何摆放,其实就是子组件对齐方式,可选值有:

    • CrossAxisAlignment.start:子组件在 Row 中顶部对齐。
    • CrossAxisAlignment.end:子组件在 Row 中底部对齐。
    • CrossAxisAlignment.center:子组件在 Row 中居中对齐。
    • CrossAxisAlignment.stretch:拉伸填充满父布局。
    • CrossAxisAlignment.baseline:在 Row 组件中会报错。
  • mainAxisAlignment:子组件沿着 Main 轴(在 Row 中是横轴)如何摆放,其实就是子组件排列方式,可选值有:

    • MainAxisAlignment.start:靠左排列。
    • MainAxisAlignment.end:靠右排列。
    • MainAxisAlignment.center:居中排列。
    • MainAxisAlignment.spaceAround:每个子组件左右间隔相等,也就是 margin 相等。
    • MainAxisAlignment.spaceBetween:两端对齐,也就是第一个子组件靠左,最后一个子组件靠右,剩余组件在中间平均分散排列。
    • MainAxisAlignment.spaceEvenly:每个子组件平均分散排列,也就是宽度相等。
  • mainAxisSize:Main 轴大小,可选值有:

    • MainAxisSize.max:相当于 Android 的 match_parent。
    • MainAxisSize.min:相当于 Android 的 wrap_content。
  • textBaseline:不太理解。

  • textDirection:子组件排列顺序,可选值有:

    • TextDirection.ltr:从左往右开始排列。
    • TextDirection.rtl:从右往左开始排列。
  • verticalDirection:确定如何在垂直方向摆放子组件,以及如何解释 start 和 end,指定 height 可以看到效果,可选值有:

    • VerticalDirection.up:Row 从下至上开始摆放子组件,此时我们看到的底部其实是顶部。
    • VerticalDirection.down:Row 从上至下开始摆放子组件,此时我们看到的顶部就是顶部。
  • children:子组件,值是一个 Widget 数组。

# 3.2.3 Demo Code

import "package:flutter/material.dart";

class MyRow extends StatelessWidget {
  const MyRow({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Row Test",
      home: Scaffold(
          appBar: AppBar(
            title: const Text("Row Demo"),
          ),
          body: Row(
            children: [
              Expanded(
                flex: 3,
                child: Container(
                  color: Colors.red,
                  height: 50,
                  child: const Text(
                    "Row 1",
                    textAlign: TextAlign.center,
                  ),
                ),
              ),
              Expanded(
                flex: 2,
                child: Container(
                  height: 50,
                  color: Colors.amber,
                  child: const Text("Row 2"),
                ),
              ),
              Expanded(
                flex: 1,
                child: Container(
                  height: 50,
                  color: Colors.blue,
                  child: const Text("Row 3"),
                ),
              ),
            ],
          )),
    );
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 3.2.4 效果图

# 3.3 Column

Column可以在垂直方向排列其子组件。参数和Row一样,不同的是子组件的布局方向为垂直,主轴和纵轴相对于Row正好相反。

# 3.3.1 定义

# 3.3.2 常用属性

# 3.3.3 Demo Code

import "package:flutter/material.dart";

class MyColumn extends StatelessWidget {
  const MyColumn(Key? key) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text(
            "Column Demo",
          ),
        ),
        body: Column(
          children: [
            const Text(
              "this is demo",
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
            Image.asset("images/demo/gyy.jpeg"),
            Container(
              height: 50,
              color: Colors.blue,
              alignment: Alignment.center,
              child: const Text(
                "this is container",
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 3.3.4 效果图

# 3.2.3 Expanded

class Expanded extends Flexible {
  /// Creates a widget that expands a child of a [Row], [Column], or [Flex]
  /// so that the child fills the available space along the flex widget's
  /// main axis.
  const Expanded({
    Key? key,
    int flex = 1,
    required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
}
1
2
3
4
5
6
7
8
9
10

# 3.3 Stack

Stack widget 不是线性(水平或垂直)定位的,而是按照绘制顺序将 widget 堆叠在一起。你可以用 Positioned widget 作为Stack 的子 widget,以相对于 Stack 的上,右,下,左来定位它们。 Stack 是基于 Web 中的绝对位置布局模型设计的。


1

# 3.4 Container

Container widget 可以用来创建一个可见的矩形元素。 Container 可以使用 BoxDecoration 来进行装饰,如背景,边框,或阴影等。 Container 还可以设置外边距、内边距和尺寸的约束条件等。另外,Container可以使用矩阵在三维空间进行转换。


1

# 4. StatefulWidget

更新时间: 1/9/2023, 5:35:51 PM