Widget 基础
Widget 是 Flutter 应用的构建块。理解 Widget 的概念和工作原理是掌握 Flutter 的关键。Flutter 3.28+ 提供了更多优化和新特性。
1. 什么是 Widget?
Widget 是 Flutter 中的核心概念,它们是:
- UI 元素:按钮、文本、图片等
- 布局组件:行、列、堆栈等
- 功能组件:手势、主题、导航等
- 不可变的:一旦创建就不能修改
2. Widget 类型
StatelessWidget(无状态 Widget)
无状态 Widget 是不可变的,一旦创建就不会改变。适用于静态内容。
import 'package:flutter/material.dart';
class MyTextWidget extends StatelessWidget {
final String text;
const MyTextWidget({super.key, required this.text});
@override
Widget build(BuildContext context) {
return Text(
text,
style: const TextStyle(
fontSize: 18,
color: Colors.blue,
),
);
}
}
// 使用
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MyTextWidget(text: 'Hello, Widget!'),
),
),
);
}
}
StatefulWidget(有状态 Widget)
有状态 Widget 可以在其生命周期内改变状态。适用于需要动态更新的内容。
import 'package:flutter/material.dart';
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'计数: $_count',
style: const TextStyle(fontSize: 24),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _increment,
child: const Text('增加'),
),
],
);
}
}
3. 基础组件概览
以下是 Flutter 中最常用的基础组件,每个组件都有其特定的用途和特点。
📚 基础组件详解
📝 Text - 文本组件
Text 是最常用的组件之一,用于显示文本内容。支持丰富的样式定制,包括字体大小、颜色、字重、对齐方式等。
Text(
'Hello Flutter',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
)
🖼️ Image - 图片组件
Image 组件用于显示图片,支持多种来源:网络图片、本地资源、内存图片等。提供丰富的 fit 模式控制图片缩放。
Image.network(
'https://example.com/image.png',
fit: BoxFit.cover,
width: 200,
height: 200,
)
⭐ Icon - 图标组件
Icon 组件用于显示 Material Design 图标,可以设置颜色、大小等属性。使用 Icons 类可以访问预定义的图标集。
Icon(
Icons.favorite,
color: Colors.red,
size: 48,
)
📦 Container - 容器组件
Container 是一个多功能组合组件,可以设置内边距、外边距、装饰、约束等。是布局中最常用的组件之一。
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 10,
)
]
),
)
↔️ Padding - 间距组件
Padding 用于在子组件周围添加内边距。可以设置统一值,也可以分别设置四个方向的值。
Padding(
padding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 8
),
child: Text('Hello'),
)
📏 SizedBox - 尺寸组件
SizedBox 用于设置子组件的固定尺寸,或作为空白占位符。常用于控制间距和布局。
// 设置固定尺寸
SizedBox(
width: 100,
height: 50,
child: Text('Box'),
)
// 作为间距
SizedBox(height: 16)
4. 常用基础 Widget(详细)
Container
Container 是一个多功能组合 Widget,可以包含子 Widget、设置内边距、外边距、装饰等。
Container(
width: 200,
height: 200,
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 10,
spreadRadius: 5,
),
],
),
child: const Center(
child: Text(
'Container',
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
)
Text
Text Widget 用于显示文本内容。
📐 Text 渲染效果
const Text(
'Hello, Flutter!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
letterSpacing: 1.5,
wordSpacing: 2.0,
),
textAlign: TextAlign.center,
)
📋 Text 核心属性
| 属性 | 类型 | 说明 | 常用值 |
|---|---|---|---|
| style | TextStyle | 文本样式 | TextStyle() |
| textAlign | TextAlign | 文本对齐方式 | center, left, right |
| maxLines | int | 最大行数 | 1, 2, 3... |
| overflow | TextOverflow | 溢出处理 | ellipsis, fade, clip |
| textDirection | TextDirection | 文本方向 | ltr, rtl |
| softWrap | bool | 是否自动换行 | true, false |
| strutStyle | StrutStyle | 段落样式 | StrutStyle() |
🎨 TextStyle 核心属性
| 属性 | 类型 | 说明 | 常用值 |
|---|---|---|---|
| fontSize | double | 字体大小 | 14, 16, 18... |
| fontWeight | FontWeight | 字体粗细 | bold, normal, w500 |
| color | Color | 字体颜色 | Colors.blue, Color(0xFF...) |
| letterSpacing | double | 字母间距 | 1.0, 1.5, 2.0... |
| wordSpacing | double | 单词间距 | 1.0, 2.0, 3.0... |
| height | double | 行高 | 1.0, 1.2, 1.5... |
| fontFamily | String | 字体族 | Roboto, Arial... |
| decoration | TextDecoration | 文本装饰 | underline, lineThrough... |
Image
Image Widget 用于显示图片。
📐 Image 渲染效果
// 从网络加载图片
Image.network(
'https://example.com/image.jpg',
width: 200,
height: 200,
fit: BoxFit.cover,
)
// 从资源加载图片
Image.asset('assets/images/logo.png')
// 从文件加载
Image.file(File('/path/to/image.jpg'))
📋 Image 核心属性
| 属性 | 类型 | 说明 | 常用值 |
|---|---|---|---|
| width | double | 图片宽度 | 100, 200, 300... |
| height | double | 图片高度 | 100, 200, 300... |
| fit | BoxFit | 图片填充方式 | cover, contain, fill... |
| color | Color | 图片颜色 | Colors.blue, Colors.red... |
| alignment | AlignmentGeometry | 对齐方式 | center, topLeft, bottomRight... |
| repeat | ImageRepeat | 图片重复方式 | noRepeat, repeat, repeatX... |
| semanticLabel | String | 语义标签 | "用户头像", "产品图片"... |
| filterQuality | FilterQuality | 图片质量 | low, medium, high, none |
| opacity | double | 透明度 | 0.0-1.0 |
🎯 BoxFit 详解
| 值 | 说明 | 效果 |
|---|---|---|
| fill | 完全填充,不保持宽高比 | 可能变形 |
| cover | 保持宽高比,完全覆盖 | 可能裁剪 |
| contain | 保持宽高比,完整显示 | 可能留白 |
| fitWidth | 保持宽度,高度自适应 | 宽度对齐 |
| fitHeight | 保持高度,宽度自适应 | 高度对齐 |
| none | 不进行缩放 | 原始大小 |
| scaleDown | 缩小图片以适应容器 | 不放大 |
Icon
Icon Widget 显示图标。
📐 Icon 渲染效果
const Icon(
Icons.favorite,
size: 48,
color: Colors.red,
)
// 自定义颜色和大小
Icon(
Icons.star,
color: Colors.yellow,
size: 32,
)
📋 Icon 核心属性
| 属性 | 类型 | 说明 | 常用值 |
|---|---|---|---|
| icon | IconData | 图标数据 | Icons.star, Icons.home... |
| size | double | 图标大小 | 16, 24, 32, 48... |
| color | Color | 图标颜色 | Colors.blue, Colors.red... |
| semanticLabel | String | 语义标签 | "收藏", "设置"... |
| textDirection | TextDirection | 文本方向 | ltr, rtl |
| shadows | List<Shadow> | 阴影效果 | [Shadow(blur: 10...)] |
| applyTextScaling | bool | 是否应用文本缩放 | true, false |
| grade | int | 图标等级 | 0-255 |
| weight | int | 图标权重 | 100-900 |
| opticalSize | int | 光学尺寸 | 20-48 |
| fill | double | 填充程度 | 0.0-1.0 |
🎨 常用图标集
| 图标集 | 说明 | 示例 |
|---|---|---|
| Material Icons | Material Design 官方图标 | Icons.star, Icons.home |
| Cupertino Icons | iOS 风格图标 | CupertinoIcons.heart |
| Font Awesome | Font Awesome 图标 | FontAwesomeIcons.star |
| 自定义图标 | 使用自定义字体文件 | IconData(0xe800, fontFamily: 'MyFont') |
4. 交互 Widget
按钮
Flutter 提供了多种按钮类型。
// ElevatedButton(Material 风格凸起按钮)
ElevatedButton(
onPressed: () {
print('ElevatedButton 被点击');
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 15,
),
),
child: const Text('点击我'),
)
// TextButton(文本按钮)
TextButton(
onPressed: () {},
child: const Text('文本按钮'),
)
// OutlinedButton(轮廓按钮)
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.blue),
),
child: const Text('轮廓按钮'),
)
// IconButton(图标按钮)
IconButton(
onPressed: () {},
icon: const Icon(Icons.favorite),
iconSize: 32,
color: Colors.red,
)
TextField
TextField Widget 用于接收用户输入。
TextField(
decoration: InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
prefixIcon: const Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.grey[100],
),
onChanged: (value) {
print('输入: $value');
},
onSubmitted: (value) {
print('提交: $value');
},
)
5. Widget 树
Flutter 应用的 UI 由 Widget 树组成。理解 Widget 树对于构建复杂 UI 至关重要。
6. 生命周期
理解 StatefulWidget 的生命周期对于管理状态和资源很重要。
class LifecycleWidget extends StatefulWidget {
const LifecycleWidget({super.key});
@override
State createState() => _LifecycleWidgetState();
}
class _LifecycleWidgetState extends State {
@override
void initState() {
super.initState();
print('initState: Widget 初始化');
// 初始化操作,如加载数据
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies: 依赖变化');
// 依赖项(如 Theme)变化时调用
}
@override
void didUpdateWidget(LifecycleWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget: Widget 更新');
// 父 Widget 重建时调用
}
@override
void setState(VoidCallback fn) {
super.setState(fn);
print('setState: 状态更新');
}
@override
void deactivate() {
super.deactivate();
print('deactivate: Widget 即将被移除');
}
@override
void dispose() {
super.dispose();
print('dispose: Widget 被销毁');
// 清理资源,如关闭流、取消订阅
}
@override
Widget build(BuildContext context) {
print('build: Widget 构建');
return Container(
child: const Text('生命周期示例'),
);
}
}
⏱️ StatefulWidget 生命周期时序图
📊 Widget 类型对比
| 特性 | StatelessWidget | StatefulWidget |
|---|---|---|
| 状态 | 不可变 | 可变 |
| 生命周期 | 简单(仅 build) | 复杂(多个阶段) |
| 性能 | 更好 | 较重 |
| 使用场景 | 静态内容 | 动态交互 |
| 状态管理 | 依赖父组件 | 自身管理 |
7. 最佳实践
- 合理拆分 Widget:将大 Widget 拆分成小的、可重用的组件
- 使用 const:对于不变的 Widget 使用 const 构造函数
- 避免过度嵌套:使用私有方法或独立 Widget 减少嵌套层级
- 选择合适的状态管理:根据应用复杂度选择 setState、Provider、Bloc 等
- 使用 Keys:在需要控制 Widget 身份时使用 Key