Flutter 自定义组件的基本概念
自定义组件是 Flutter 中通过组合现有组件或从头构建新组件的方式实现特定功能。通常通过继承 StatelessWidget 或 StatefulWidget 实现,前者用于无状态组件,后者用于需要动态更新的组件。
创建无状态自定义组件
无状态组件继承 StatelessWidget,通过 build 方法返回一个组件树。适合静态展示内容。
dart
class CustomButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
const CustomButton({required this.text, required this.onPressed});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(text),
);
}
}
创建有状态自定义组件
有状态组件继承 StatefulWidget,并搭配一个 State 类管理动态数据。通过 setState 触发界面更新。
dart
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}
组合现有组件构建复杂 UI
通过组合 Row、Column、Container 等基础组件,实现更复杂的自定义组件。
dart
class CustomCard extends StatelessWidget {
final String title;
final String description;
const CustomCard({required this.title, required this.description});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: Theme.of(context).textTheme.headline6),
const SizedBox(height: 8),
Text(description),
],
),
),
);
}
}
使用参数化设计提高复用性
通过构造函数传递参数(如颜色、尺寸、回调函数),使组件更灵活。
dart
class CustomIconButton extends StatelessWidget {
final IconData icon;
final Color color;
final VoidCallback onPressed;
const CustomIconButton({
required this.icon,
this.color = Colors.blue,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(icon, color: color),
onPressed: onPressed,
);
}
}
注意事项
- 性能优化 :避免在
build方法中执行耗时操作,将复杂逻辑移至initState或异步函数。 - 主题一致性 :使用
Theme.of(context)获取全局样式,保持应用风格统一。 - 文档注释 :为自定义组件添加
///文档注释,说明用途和参数含义。
一、添加 UI 组件
在进行自定义组件的封装之前,应该先掌握如何在 Flutter 应用页面中添加内置组件,如按钮和文本等,以下面的页面定义为例:
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text("Hello Word!");
}
}
由于 dart 语法规定了方法返回值只能一个,所以无法通过简单地返回多个 Text 组件,去完成页面内容的增加;而作为 UI 组件,也不支持像字符串那样通过操作符 + 进行内容的拼接,因此,想要上述代码对应的页面具有更多的内容,可行的方法就是使用容器类组件作为最终的返回值,例如下面:
java
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("文本一"),
Text("文本二"),
],
);
}
}
又或者:
java
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
children: [
Text("文本一"),
Text("文本二"),
],
);
}
}
然而,即便是容器组件,也不意味着就能够一次添加多个UI元素,因为像 Container 这种容器组件,只能声明定义一个UI元素:
java
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: (MediaQuery.of(context).size.width*0.95),
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text("Hello World"),
Text("Hello World"),
Text("Hello World"),
],
),
);
}
}
仔细对比 Container 组件和 Column 组件与 Row 组件的属性,就不难发现可以通过属性名称,去判断一个容器组件是支持多元素定义、还是单一元素定义。
对于像 Column、Row 和 ListView 等支持多元素定义的容器组件,都是用 children 作为属性名,而对于像 Container、Padding 和 Center 等支持单一元素定义的容器组件,则是用 child 作为属性名。
参考文章