Widget
什么是 Widget?
在 Flutter 中,一切皆 Widget。Widget 是 Flutter 应用程序 UI 的基本构建块。它们描述了在给定配置和状态下,视图应该看起来是什么样子。Widget 可以是可见的 UI 元素(如文本、按钮、图片),也可以是不可见的布局元素(如行、列、填充)。
Widget 是不可变的,这意味着一旦创建,它们的属性就不能改变。当 Widget 的状态发生变化时,Flutter 会创建一个新的 Widget 树来表示新的 UI 状态,然后高效地更新屏幕。
Widget 的分类
Widget 主要分为两大类:
- StatefulWidget (有状态 Widget)
- StatelessWidget (无状态 Widget)
- InheritedWidget (继承 Widget)
1. StatelessWidget (无状态 Widget)
StatelessWidget
是没有内部状态的 Widget。它们一旦被创建,其属性就不能改变。它们通常用于显示静态内容,或者其状态由父 Widget 管理。
特点:
- 不依赖于任何可变状态。
- 生命周期简单,通常只构建一次。
- 适用于静态内容,如图标、文本、图片等。
示例: Text
, Icon
, Image
, AppBar
, Padding
, Row
, Column
dart
import 'package:flutter/material.dart';
class MyStatelessWidget extends StatelessWidget {
final String title;
const MyStatelessWidget({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: const Center(
child: Text('这是一个无状态 Widget'),
),
);
}
}
void main() {
runApp(const MaterialApp(home: MyStatelessWidget(title: '无状态示例')));
}
2. StatefulWidget (有状态 Widget)
StatefulWidget
是有状态的 Widget,它们的状态可以随着时间的推移而改变。当状态发生变化时,Flutter 会创建一个新的 Widget 树来表示新的 UI 状态,然后高效地更新屏幕。
特点:
- 可以拥有可变状态,状态可以在 Widget 的生命周期内改变。
- 生命周期相对复杂,包括创建、更新、销毁等阶段。
- 适用于需要用户交互或数据动态变化的场景,如计数器、表单输入等。
示例: Checkbox
, Slider
, TextField
, ListView
, InkWell
dart
import 'package:flutter/material.dart';
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('有状态示例'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'您已经点击按钮这么多次:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
void main() {
runApp(const MaterialApp(home: MyStatefulWidget()));
}
Widget
Text
: 显示一段文本。Icon
: 显示一个图标。Image
: 显示一张图片。Button
(如ElevatedButton
,TextButton
,OutlinedButton
) : 用户可点击的按钮。Container
: 一个方便的 Widget,可以组合绘制、定位和大小调整 Widget。Row
: 将子 Widget 水平排列。Column
: 将子 Widget 垂直排列。Stack
: 允许子 Widget 堆叠在一起,可以用于创建重叠的 UI 元素。Padding
: 给子 Widget 添加内边距。Scaffold
: 实现基本的 Material Design 视觉布局结构,包含 AppBar , body , FloatingActionButton 等。ListView
: 可滚动的列表,适用于显示大量内容。GestureDetector
: 检测用户手势,如点击、双击、长按等。
文本和图像
dart
Text(
'Hello, Flutter!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
)
dart
Icon(
Icons.favorite,
color: Colors.red,
size: 48,
)
dart
// 从网络加载图片
Image.network('https://example.com/image.jpg')
// 从本地资源加载图片
Image.asset('assets/images/logo.png')
dart
// ElevatedButton
ElevatedButton(
onPressed: () {
print('Button pressed!');
},
child: Text('Elevated Button'),
)
// TextButton
TextButton(
onPressed: () {},
child: Text('Text Button'),
)
// OutlinedButton
OutlinedButton(
onPressed: () {},
child: Text('Outlined Button'),
)
FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
tooltip: 'Add',
)
页面结构
dart
Scaffold(
appBar: AppBar(
title: Text('Scaffold Example'),
),
body: Center(
child: Text('Main Content'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
)
dart
// 通常用于 Scaffold 的顶部,显示标题、操作按钮等
AppBar(
title: Text('AppBar Example'),
actions: [
IconButton(
icon: Icon(Icons.settings),
onPressed: () {},
),
],
)
dart
// 用于在底部创建一个导航栏,通常用于切换不同的页面或功能
BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
],
)
布局
dart
Container(
width: 200,
height: 200,
color: Colors.amber,
padding: EdgeInsets.all(16),
margin: EdgeInsets.all(8),
child: Text('Container Content'),
)
dart
Padding(
padding: EdgeInsets.all(16),
child: Text('Padded Text'),
)
dart
Center(
child: Container(
width: 200,
height: 200,
color: Colors.blue,
child: Center(
child: Text('双重居中'),
),
),
)
dart
SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.red,
),
)
SizedBox.expand(
child: Container(
color: Colors.green,
),
)
SizedBox.shrink()
dart
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
Icon(Icons.star, color: Colors.yellow),
],
)
dart
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('First Item'),
Text('Second Item'),
Text('Third Item'),
],
)
dart
Stack(
children: [
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
bottom: 10,
right: 10,
child: Icon(Icons.add_circle, color: Colors.white, size: 48),
),
],
)
dart
Expanded(
flex: 1, // 占据剩余空间的 1 份
child: Container(
color: Colors.red,
child: const Center(child: Text('Expanded (flex: 1)', style: TextStyle(color: Colors.white))),
),
dart
Flexible( // 红色方块会根据内容大小灵活伸缩,但不强制填满
flex: 1,
fit: FlexFit.loose, // 允许它更灵活地根据内容决定大小
child: Container(color: Colors.red, child: Text('短文本')),
),
Flexible( // 绿色方块也会根据内容大小灵活伸缩
flex: 1,
fit: FlexFit.loose,
child: Container(color: Colors.green, child: Text('一段比较长的文本,可能会自动换行')),
),
dart
Row(
children: <Widget>[
Text('左边'),
Spacer(), // 填充左右文本之间的所有剩余空间
Text('右边'),
],
)
// 或者均匀分布
Row(
children: <Widget>[
Text('A'),
Spacer(), // 弹性空间1
Text('B'),
Spacer(flex: 2), // 弹性空间2,比空间1大一倍
Text('C'),
],
)
输入交互
dart
// 用于创建单行文本输入框,用户可以在其中输入文本。
TextField(
decoration: InputDecoration(
hintText: 'Enter your text',
labelText: 'Text Input',
),
)
dart
// 用于创建可验证的文本输入框,通常与 Form 一起使用,用于收集用户输入并进行验证。
TextFormField(
decoration: InputDecoration(
hintText: 'Enter your email',
labelText: 'Email Input',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
return null;
},
)
dart
// 复选框,用于用户选择多个选项中的一个或多个。
Checkbox(
value: isChecked,
onChanged: (newValue) {
setState(() {
isChecked = newValue!;
});
},
)
dart
// 单选框,用于用户选择多个选项中的一个。
enum SingingCharacter { lafayette, jefferson }
SingingCharacter? _character = SingingCharacter.lafayette; // 状态变量
// ... 在 build 方法中 ...
Radio<SingingCharacter>(
value: SingingCharacter.lafayette,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
)
列表和滚动
dart
// 常用的可滚动列表,适用于显示大量动态内容。可以一次性构建所有子项 (ListView),也可以按需构建 (ListView.builder) 以提高性能。
ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item \$index'),
);
},
)
dart
// 用于在单个子项的情况下创建可滚动视图,适用于只有一个子项的情况。
SingleChildScrollView(
child: Column(
children: [
Text('SingleChildScrollView Example'),
// 这里添加更多内容
],
),
)
dart
ListView.builder(
itemCount: 100, // 列表项的总数量,如果是无限列表,可以省略或给一个很大的值
itemBuilder: (BuildContext context, int index) {
// 这个 builder 函数会为每个索引构建一个列表项
return ListTile(
title: Text('列表项 ${index + 1}'),
subtitle: Text('这是第 $index 个数据'),
leading: Icon(Icons.star),
);
},
);
dart
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // 每行/列显示2个
crossAxisSpacing: 10.0, // 交叉轴间距
mainAxisSpacing: 10.0, // 主轴间距
),
itemCount: 50, // 网格项的总数量
itemBuilder: (BuildContext context, int index) {
// 这个 builder 函数会为每个索引构建一个网格项
return Card(
color: Colors.primaries[index % Colors.primaries.length], // 随机颜色
child: Center(
child: Text('格子 $index', style: const TextStyle(color: Colors.white, fontSize: 20)),
),
);
},
);
手势检测
dart
GestureDetector(
onTap: () {
print('Tapped!');
},
onDoubleTap: () {
print('Double tapped!');
},
onLongPress: () {
print('Long pressed!');
},
child: Container(
width: 200,
height: 200,
color: Colors.green,
child: Center(child: Text('Tap Me')),
),
)
进度指示器
dart
// 用于显示圆形进度指示器,通常用于表示加载操作或等待时间。
CircularProgressIndicator(
value: 0.5, // 进度值,范围为 0.0 到 1.0
backgroundColor: Colors.grey, // 背景颜色
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), // 进度颜色
)
dart
// 用于显示线性进度指示器,通常用于表示加载操作或等待时间。
LinearProgressIndicator(
value: 0.75, // 进度值,范围为 0.0 到 1.0
backgroundColor: Colors.grey, // 背景颜色
valueColor: AlwaysStoppedAnimation<Color>(Colors.green), // 进度颜色
)
消息通知
dart
// 用于显示短暂的消息通知,通常用于向用户展示操作成功或失败的消息。
SnackBar(
content: Text('This is a SnackBar message'),
duration: Duration(seconds: 2),
)
dart
AlertDialog(
title: Text('AlertDialog Example'),
content: Text('This is an AlertDialog content'),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Cancel'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('OK'),
),
],
)