Flutter 小白入门教程Flutter 小白入门教程
首页
学习指南
项目实战
Flutter 官网
编程指南
首页
学习指南
项目实战
Flutter 官网
编程指南
  • 入门基础

    • 📚 基础教程
    • 第1章 - 认识 Flutter
    • 第2章 - 环境搭建
    • 第3章 - Dart 语言基础
    • 第4章 - 第一个 Flutter 应用
    • 第5章 - Widget 基础
    • 第6章 - 布局系统
    • 第7章 - 状态管理入门
    • 第8章 - 页面导航
    • 第9章 - 资源管理
  • 进阶开发

    • 第10章 - 网络请求
    • 第11章 - 本地存储
    • 第12章 - 对话框与反馈
    • 第13章 - 列表进阶
    • 第14章 - 主题定制
    • 第15章 - 状态管理进阶
    • 第16章 - 动画入门
    • 第17章 - 常用第三方包
  • 调试与发布

    • 第18章 - 调试与性能优化
    • 第19章 - 打包与发布
  • 附录

    • 附录A - UI 框架与组件库推荐
    • 附录B - 项目结构最佳实践
    • 附录C - 国际化配置
    • 附录D - 权限处理

第5章 - Widget 基础

嗨,朋友!我是长安。

上一章我们创建了第一个 Flutter 应用,接触了一些基本组件。这一章,我们来系统地学习 Flutter 中最重要的概念——Widget。

🤔 什么是 Widget?

在 Flutter 中,Widget 就是构建 UI 的基本单元。

你可以把 Widget 想象成乐高积木:

  • 每一块积木都是一个 Widget
  • 小积木可以组合成大积木
  • 大积木可以组合成更大的作品
  • 最终搭建出完整的界面
Flutter UI = Widget + Widget + Widget + ...

核心理念

在 Flutter 中,一切皆 Widget!文字是 Widget,按钮是 Widget,图片是 Widget,甚至布局、间距、动画都是 Widget。

🎭 Widget 的两种类型

1. StatelessWidget(无状态组件)

特点:创建后不会改变,没有可变的状态

适用场景:纯展示性的内容,如文字、图标、静态图片

class MyTitle extends StatelessWidget {
  final String text;
  
  const MyTitle({super.key, required this.text});

  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      style: const TextStyle(
        fontSize: 24,
        fontWeight: FontWeight.bold,
      ),
    );
  }
}

// 使用
MyTitle(text: '我是标题')

2. StatefulWidget(有状态组件)

特点:可以动态改变内容,有可变的状态

适用场景:需要交互或数据变化的内容,如计数器、表单、动画

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _count = 0;  // 状态数据

  void _increment() {
    setState(() {  // 调用 setState 更新 UI
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('计数:$_count', style: const TextStyle(fontSize: 24)),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('加一'),
        ),
      ],
    );
  }
}

重要

修改 StatefulWidget 的状态时,必须使用 setState() 方法,否则 UI 不会更新!

📦 常用基础 Widget

1. Text - 文本

// 基础用法
Text('Hello Flutter')

// 带样式
Text(
  '带样式的文本',
  style: TextStyle(
    fontSize: 20,           // 字体大小
    fontWeight: FontWeight.bold,  // 粗体
    color: Colors.blue,     // 颜色
    letterSpacing: 2,       // 字间距
    decoration: TextDecoration.underline,  // 下划线
  ),
)

// 多行文本
Text(
  '这是一段很长很长的文本,会自动换行显示',
  maxLines: 2,              // 最多显示行数
  overflow: TextOverflow.ellipsis,  // 超出显示省略号
  textAlign: TextAlign.center,      // 居中对齐
)

2. Icon - 图标

// 基础图标
Icon(Icons.favorite)

// 带样式
Icon(
  Icons.star,
  size: 40,
  color: Colors.amber,
)

// Flutter 内置了大量 Material 图标
// 查看所有图标:https://fonts.google.com/icons

常用图标:

图标代码
❤️Icons.favorite
⭐Icons.star
🏠Icons.home
⚙️Icons.settings
🔍Icons.search
➕Icons.add
✏️Icons.edit
🗑️Icons.delete

3. Image - 图片

// 网络图片
Image.network(
  'https://example.com/image.png',
  width: 200,
  height: 200,
  fit: BoxFit.cover,  // 填充方式
)

// 本地图片(需要先在 pubspec.yaml 中声明)
Image.asset('assets/images/logo.png')

// 占位图和错误图
Image.network(
  'https://example.com/image.png',
  loadingBuilder: (context, child, progress) {
    if (progress == null) return child;
    return const CircularProgressIndicator();
  },
  errorBuilder: (context, error, stackTrace) {
    return const Icon(Icons.error);
  },
)

4. Button - 按钮

// 凸起按钮(主要操作)
ElevatedButton(
  onPressed: () {
    print('点击了');
  },
  child: const Text('ElevatedButton'),
)

// 文字按钮(次要操作)
TextButton(
  onPressed: () {},
  child: const Text('TextButton'),
)

// 边框按钮
OutlinedButton(
  onPressed: () {},
  child: const Text('OutlinedButton'),
)

// 图标按钮
IconButton(
  onPressed: () {},
  icon: const Icon(Icons.thumb_up),
)

// 浮动操作按钮
FloatingActionButton(
  onPressed: () {},
  child: const Icon(Icons.add),
)

// 带图标的按钮
ElevatedButton.icon(
  onPressed: () {},
  icon: const Icon(Icons.send),
  label: const Text('发送'),
)

5. TextField - 输入框

// 基础输入框
TextField(
  decoration: const InputDecoration(
    labelText: '用户名',
    hintText: '请输入用户名',
    prefixIcon: Icon(Icons.person),
  ),
)

// 密码输入框
TextField(
  obscureText: true,  // 隐藏输入内容
  decoration: const InputDecoration(
    labelText: '密码',
    prefixIcon: Icon(Icons.lock),
  ),
)

// 获取输入内容
class MyForm extends StatefulWidget {
  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  final _controller = TextEditingController();

  @override
  void dispose() {
    _controller.dispose();  // 记得释放
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(controller: _controller),
        ElevatedButton(
          onPressed: () {
            print('输入内容:${_controller.text}');
          },
          child: const Text('提交'),
        ),
      ],
    );
  }
}

6. Container - 容器

Container 是一个多功能的容器组件,可以设置尺寸、边距、背景、边框等。

Container(
  width: 200,
  height: 100,
  margin: const EdgeInsets.all(10),      // 外边距
  padding: const EdgeInsets.all(20),     // 内边距
  decoration: BoxDecoration(
    color: Colors.blue,                  // 背景色
    borderRadius: BorderRadius.circular(10),  // 圆角
    boxShadow: [                         // 阴影
      BoxShadow(
        color: Colors.black26,
        blurRadius: 10,
        offset: const Offset(0, 5),
      ),
    ],
  ),
  child: const Text(
    'Container 示例',
    style: TextStyle(color: Colors.white),
  ),
)

7. Card - 卡片

Card(
  elevation: 4,  // 阴影高度
  margin: const EdgeInsets.all(10),
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      children: [
        const Text('卡片标题', style: TextStyle(fontSize: 18)),
        const SizedBox(height: 10),
        const Text('卡片内容描述...'),
        const SizedBox(height: 10),
        ElevatedButton(
          onPressed: () {},
          child: const Text('操作'),
        ),
      ],
    ),
  ),
)

8. ListTile - 列表项

ListTile(
  leading: const CircleAvatar(
    child: Icon(Icons.person),
  ),
  title: const Text('长安'),
  subtitle: const Text('Flutter 开发者'),
  trailing: const Icon(Icons.arrow_forward_ios),
  onTap: () {
    print('点击了列表项');
  },
)

🎨 样式技巧

EdgeInsets - 边距

// 四边相同
EdgeInsets.all(16)

// 水平/垂直
EdgeInsets.symmetric(horizontal: 20, vertical: 10)

// 单独设置
EdgeInsets.only(left: 10, top: 20)

// 分别设置
EdgeInsets.fromLTRB(10, 20, 10, 20)  // 左、上、右、下

BoxDecoration - 装饰

BoxDecoration(
  color: Colors.white,                    // 背景色
  gradient: LinearGradient(              // 渐变背景
    colors: [Colors.blue, Colors.purple],
  ),
  borderRadius: BorderRadius.circular(12), // 圆角
  border: Border.all(color: Colors.grey),  // 边框
  boxShadow: [                            // 阴影
    BoxShadow(
      color: Colors.black12,
      blurRadius: 8,
      offset: Offset(0, 4),
    ),
  ],
  image: DecorationImage(                 // 背景图
    image: NetworkImage('url'),
    fit: BoxFit.cover,
  ),
)

📝 小结

这一章我们学习了:

  • ✅ Widget 的概念:Flutter UI 的基本构建单元
  • ✅ StatelessWidget vs StatefulWidget 的区别
  • ✅ 常用基础 Widget:Text、Icon、Image、Button、TextField、Container、Card、ListTile
  • ✅ 样式相关:EdgeInsets、BoxDecoration

💪 练习题

  1. 创建一个 StatefulWidget,实现一个点赞功能(点击爱心图标,数字加一,图标变红)
  2. 使用 Card 和 ListTile 创建一个简单的联系人列表(至少 3 个联系人)
  3. 创建一个带有输入框和按钮的表单,点击按钮时弹出输入的内容
点击查看答案

练习1:点赞功能

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool _isLiked = false;
  int _likeCount = 0;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        IconButton(
          onPressed: () {
            setState(() {
              _isLiked = !_isLiked;
              _likeCount += _isLiked ? 1 : -1;
            });
          },
          icon: Icon(
            _isLiked ? Icons.favorite : Icons.favorite_border,
            color: _isLiked ? Colors.red : Colors.grey,
          ),
        ),
        Text('$_likeCount'),
      ],
    );
  }
}

练习2:联系人列表

ListView(
  children: const [
    Card(
      child: ListTile(
        leading: CircleAvatar(child: Text('张')),
        title: Text('张三'),
        subtitle: Text('13800138001'),
        trailing: Icon(Icons.phone),
      ),
    ),
    Card(
      child: ListTile(
        leading: CircleAvatar(child: Text('李')),
        title: Text('李四'),
        subtitle: Text('13800138002'),
        trailing: Icon(Icons.phone),
      ),
    ),
    Card(
      child: ListTile(
        leading: CircleAvatar(child: Text('王')),
        title: Text('王五'),
        subtitle: Text('13800138003'),
        trailing: Icon(Icons.phone),
      ),
    ),
  ],
)

🚀 下一步

掌握了基础 Widget 后,下一章我们来学习 布局系统,让这些组件整齐地排列起来!


由 编程指南 提供

最近更新: 2026/2/3 16:24
Contributors: 王长安
Prev
第4章 - 第一个 Flutter 应用
Next
第6章 - 布局系统