2. 使用StatelessWidget构建静态个人名片页面

StatelessWidget 与 Widget 树:名片页面的结构拆解

静态名片页面的本质是一棵由 StatelessWidget 组合而成的 Widget 树。根节点是自定义的 BusinessCard,它不持有任何可变状态,只负责把 Scaffold、Column、CircleAvatar、Text、Icon 等基础组件按层级拼装起来。理解这棵树,比记住每个组件的构造参数更重要。

BusinessCard 的 Widget 树结构 StatelessWidget 只描述“长什么样”,不持有可变状态 BusinessCard (StatelessWidget) Scaffold appBar: AppBar(title: Text('个人名片')) Column mainAxisAlignment: center CircleAvatar radius: 50 backgroundImage Text '张明' fontSize: 28 Text 'Flutter 开发工程师' fontSize: 16 Row Icon(Icons.email) + Text('zhang@ex.com') 关键约束 • 所有节点均为 StatelessWidget 或基础组件,无 setState、无 State 对象 • build() 方法只依赖构造参数,相同输入永远渲染相同界面 • 修改名片内容需重建整个 Widget 树,而非局部刷新

从零构建名片页面

新建 lib/main.dart,入口 runApp 直接挂载 BusinessCard。整个页面只有一个自定义 Widget,其余全部由 Flutter 内置组件组合完成。

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BusinessCard(),
    ));

class BusinessCard extends StatelessWidget {
  const BusinessCard({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('个人名片'),
        centerTitle: true,
        backgroundColor: Colors.blue.shade700,
        foregroundColor: Colors.white,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const CircleAvatar(
              radius: 50,
              backgroundImage: NetworkImage('https://i.pravatar.cc/150?img=12'),
            ),
            const SizedBox(height: 20),
            const Text(
              '张明',
              style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            const Text(
              'Flutter 开发工程师',
              style: TextStyle(fontSize: 16, color: Colors.grey),
            ),
            const SizedBox(height: 24),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Icon(Icons.email, size: 18, color: Colors.blueGrey),
                SizedBox(width: 6),
                Text('zhangming@example.com',
                    style: TextStyle(fontSize: 14)),
              ],
            ),
            const SizedBox(height: 10),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Icon(Icons.phone, size: 18, color: Colors.blueGrey),
                SizedBox(width: 6),
                Text('+86 138-0000-1234',
                    style: TextStyle(fontSize: 14)),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Widget 树与渲染的对应关系

上面代码中,Column 的 children 列表顺序决定了垂直排列顺序:头像 → 姓名 → 职位 → 邮箱行 → 电话行。SizedBox 作为间距占位符,本身不绘制任何内容,只参与布局计算。每个 Row 内部用 mainAxisAlignment: center 让图标与文字水平居中。

Widget作用关键参数
Scaffold提供页面骨架与 AppBarappBar、body
CircleAvatar圆形头像容器radius、backgroundImage
Text展示姓名、职位、联系方式style.fontSize、fontWeight
Row图标与文字水平排列mainAxisAlignment
SizedBox控制元素间距height、width
头像使用 NetworkImage 需要网络权限;若在模拟器或真机上图片不显示,可换成本地 AssetImage 并配置 pubspec.yaml 的 assets 路径。

验证与观察要点

  • 运行后确认 AppBar 标题居中、头像为圆形、姓名加粗且字号明显大于职位。
  • 热重载(r)修改任意 Text 内容,界面立即更新,说明 StatelessWidget 在输入变化时整体重建。
  • 尝试在 build 中调用 setState,编译器会报错——这是 StatelessWidget 的硬性约束。
  • 把 Column 换成 ListView,观察布局行为差异,理解“无状态”不等于“不能滚动”。
不要在 StatelessWidget 中保存需要跨帧保持的数据(如计数器、输入框内容)。这类需求应交给 StatefulWidget,否则每次重建都会丢失。