02.Flutter Widget

310 阅读2分钟

在 Flutter 中,⼀切的显示都是 Widget 。Widget 是⼀切的基础,作为响应式的渲染,类似 MVVM 的实现机制。

import 'package:flutter/material.dart';

void main() {
  /// runApp 是widget树中的根节点
  /// Widget 树有两个 widgets,Center及其子widget -- Text
  runApp(
    const Center(
      child: Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

我们可以通过修改数据,再⽤ setState 设置数据,Flutter 会⾃动通过绑定的数据更新 Widget 。 所以你需要做的就是实现 Widget 界⾯,并且和数据绑定起来。

Widget 分为 有状态(StatefulWidget)⽆状态(StatelessWidget) 两种,在 Flutter 中每个⻚⾯都是⼀帧,⽆状态就是保持在那⼀帧,⽽有状态的 Widget 当数据更新时,其实是绘制了新的 Widget,只是 State 实现了跨帧的数据同步保存。

  • StatelessWidget⽆状态 widget 接收的参数来自于它的父 widget,它们储存在 final 成员变量中。当 widget 需要被 build() 时,就是用这些存储的变量为创建的 widget 生成新的参数。

  • StatefulWidget有状态 是一种特殊的 widget,它会生成 State 对象,用于保存状态。在 State 中,你可以动态改变数据,这类似 MVVM 实现,在 setState 之后,改变的数据会触发 Widget 重新构建刷新。

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(
      home: Scaffold(
    body: Center(
      child: Counter(),
    ),
  )));
}

class TextColumn1 extends StatelessWidget {
  final String? name;
  const TextColumn1({this.name, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    String defaultName = name ?? 'herry';
    return Text.rich(TextSpan(text: 'Hello ', children: <TextSpan>[
      TextSpan(
        text: '$defaultName ',
        style: const TextStyle(color: Colors.green),
      ),
      const TextSpan(
          text: 'beautiful ', style: TextStyle(fontStyle: FontStyle.italic)),
      const TextSpan(
          text: 'world ', style: TextStyle(fontWeight: FontWeight.bold))
    ]));
  }
}

class CounterDisplay extends StatelessWidget {
  final int count;
  const CounterDisplay({required this.count, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text('Count:$count');
  }
}

class CounterIncrementer extends StatelessWidget {
  final VoidCallback onPressed;
  const CounterIncrementer({required this.onPressed, Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(onPressed: onPressed, child: const Text('Increment'));
  }
}

class Counter extends StatefulWidget {
  const Counter({Key? key}) : super(key: key);

  @override
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _counter = 0;
  void _increment() {
    setState(() {
      ++_counter;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        CounterIncrementer(onPressed: _increment),
        const SizedBox(
          width: 18,
        ),
        CounterDisplay(count: _counter),
        // const TextColumn1(),  // 输出 herry
        const TextColumn1(name: 'mickey'), // 输出 mickey
      ],
    );
  }
}

State 中主要的声明周期有 :

  • initState :初始化,理论上只初始化⼀次。
  • didChangeDependencies:在 initState 之后调⽤,此时可以获取其他 State 。
  • dispose :销毁,只会调⽤⼀次。