第 4 章 核心概念:Widget 与声明式 UI

4.1 声明式 UI:你描述「长什么样」,框架负责「怎么变」

原生 Android(View 体系)是命令式的:拿到 textView 引用,手动调用 setText() 改它。Flutter 是声明式的:UI = f(state),状态变了就重新描述一遍界面,框架自动算出差异并更新。

// 状态(数据)驱动界面。state 变 → build 重新执行 → 界面更新
Text('点击了 $_count 次')  // 不需要「拿到 Text 再改它」,永远描述当前该长什么样

4.2 一切皆 Widget

文字是 Widget(Text)、按钮是 Widget(Button)、连边距、居中、行排列也都是 Widget(Padding、Center、Row)——这是与原生最大的思维差异。Widget 组成树:

MaterialApp          // 应用
 └─ Scaffold         // 页面骨架
     ├─ AppBar       // 顶栏
     └─ Center       // 居中容器
         └─ Column   // 纵向排列
             ├─ Text
             └─ ElevatedButton

4.3 StatelessWidget 与 StatefulWidget

StatelessWidget(无状态)StatefulWidget(有状态)
数据会变吗不会(构造后固定)会(配合 setState 更新)
典型场景Text、图标按钮、卡片计数器、表单、开关、倒计时
方法build()createState() + build()
import 'package:flutter/material.dart';

// 有状态组件三步曲:① 继承 StatefulWidget ② create 持有 State ③ 在 State 里 build
class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _count = 0; // 状态数据放 State 里

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('计数器')),
      body: Center(
        child: Text('点击了 $_count 次',
            style: const TextStyle(fontSize: 24)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {     // ④ 改状态必须包在 setState 里,否则界面不刷新!
            _count++;
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

void main() => runApp(const MaterialApp(home: CounterPage()));
⚠️ 新手三大高频错误 ① 忘记 setState 界面不刷新;② 在 build 里写耗时逻辑(build 会被频繁调用);③ setState 之外直接改 State 字段后预期 UI 更新。记住口诀:数据放 State,改数据用 setState。
← 上一章第 3 章 Dart 语言基础下一章 →第 5 章 常用组件详解(完整可运行示例)
✉ 联系作者:linghurongjun@sina.com