附录A - UI 框架与组件库推荐
嗨,朋友!我是长安。
作为 Flutter 小白,你可能会困惑:如何快速做出漂亮的界面? 答案就是:善用现成的 UI 框架和组件库!
这一章,我会推荐一些优秀的 UI 资源,让你的 App 瞬间变得高大上!
🎨 Flutter 内置 Material 组件
Flutter 自带了丰富的 Material Design 组件,先把这些用熟练!
Material 3 新特性
Material 3 是最新的设计规范,Flutter 3.0+ 已全面支持。
MaterialApp(
theme: ThemeData(
useMaterial3: true, // 启用 Material 3
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
home: const HomePage(),
)
常用 Material 组件一览
// 按钮系列
ElevatedButton(onPressed: () {}, child: const Text('凸起按钮'))
FilledButton(onPressed: () {}, child: const Text('填充按钮')) // M3 新增
FilledButton.tonal(onPressed: () {}, child: const Text('色调按钮')) // M3 新增
OutlinedButton(onPressed: () {}, child: const Text('轮廓按钮'))
TextButton(onPressed: () {}, child: const Text('文字按钮'))
IconButton(onPressed: () {}, icon: const Icon(Icons.add))
FloatingActionButton(onPressed: () {}, child: const Icon(Icons.add))
FloatingActionButton.extended( // M3 推荐
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('新建'),
)
// 输入框
TextField(decoration: const InputDecoration(labelText: '用户名'))
SearchBar(hintText: '搜索...') // M3 新增
// 卡片与容器
Card(child: ...)
Card.filled(child: ...) // M3 新增
Card.outlined(child: ...) // M3 新增
// 导航
NavigationBar(...) // M3 底部导航
NavigationRail(...) // M3 侧边导航
NavigationDrawer(...) // M3 抽屉导航
// 提示与反馈
SnackBar(content: Text('提示'))
AlertDialog(title: Text('标题'), content: Text('内容'))
BottomSheet(builder: ...)
// 选择器
Checkbox(value: true, onChanged: (v) {})
Switch(value: true, onChanged: (v) {})
Radio(value: 1, groupValue: 1, onChanged: (v) {})
Slider(value: 0.5, onChanged: (v) {})
DropdownMenu(...) // M3 新增
SegmentedButton(...) // M3 新增
// 进度指示
CircularProgressIndicator()
LinearProgressIndicator()
// 标签
Chip(label: Text('标签'))
FilterChip(label: Text('筛选'), selected: true, onSelected: (v) {})
InputChip(label: Text('输入'))
ActionChip(label: Text('操作'), onPressed: () {})
Material 3 配色示例
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
// 使用种子色自动生成配色方案
final colorScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4), // 品牌色
brightness: Brightness.light,
);
return MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Material 3'),
backgroundColor: colorScheme.primaryContainer,
foregroundColor: colorScheme.onPrimaryContainer,
),
body: Center(
child: FilledButton(
onPressed: () {},
child: const Text('Material 3 按钮'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
);
}
}
📦 第三方 UI 框架
GetWidget(1000+ 组件)
功能最全面的 Flutter UI 库,包含 1000+ 预构建组件。
dependencies:
getwidget: ^4.0.0
import 'package:getwidget/getwidget.dart';
// 按钮
GFButton(
onPressed: () {},
text: '按钮',
type: GFButtonType.solid,
shape: GFButtonShape.pills,
)
// 头像
GFAvatar(
backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
shape: GFAvatarShape.circle,
size: GFSize.LARGE,
)
// 徽章
GFBadge(
text: '99+',
color: GFColors.DANGER,
shape: GFBadgeShape.circle,
)
// 卡片
GFCard(
boxFit: BoxFit.cover,
image: Image.network('https://example.com/image.jpg'),
title: GFListTile(
avatar: GFAvatar(backgroundImage: NetworkImage('url')),
title: const Text('标题'),
subtitle: const Text('副标题'),
),
content: const Text('卡片内容...'),
buttonBar: GFButtonBar(
children: [
GFButton(onPressed: () {}, text: '点赞'),
GFButton(onPressed: () {}, text: '分享'),
],
),
)
// 轮播图
GFCarousel(
items: imageList.map((url) {
return Container(
margin: const EdgeInsets.all(8),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(url, fit: BoxFit.cover),
),
);
}).toList(),
autoPlay: true,
pagination: true,
)
// 评分
GFRating(
value: 3.5,
onChanged: (value) {},
size: GFSize.MEDIUM,
filledIcon: Icon(Icons.star, color: Colors.amber),
halfFilledIcon: Icon(Icons.star_half, color: Colors.amber),
defaultIcon: Icon(Icons.star_border, color: Colors.amber),
)
// 进度条
GFProgressBar(
percentage: 0.7,
lineHeight: 20,
animation: true,
animationDuration: 1000,
backgroundColor: Colors.grey[200]!,
progressBarColor: GFColors.SUCCESS,
)
// Toast
GFToast.showToast('操作成功', context);
// 骨架屏
GFShimmer(
child: Container(
height: 200,
width: double.infinity,
color: Colors.white,
),
)
GetWidget 组件分类:
| 分类 | 组件 |
|---|---|
| 基础 | Button, Avatar, Badge, Image, Card |
| 表单 | TextField, Checkbox, Radio, Switch, Rating |
| 导航 | AppBar, TabBar, BottomNav, Drawer |
| 反馈 | Toast, Loader, Shimmer, Progress |
| 展示 | Carousel, Accordion, ListTile, Typography |
| 布局 | Container, Grid, Tile, Sticky Header |
flutter_neumorphic(新拟态风格)
独特的新拟态 UI 风格。
dependencies:
flutter_neumorphic: ^3.2.0
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
// 使用 NeumorphicApp
NeumorphicApp(
title: 'Neumorphic App',
themeMode: ThemeMode.light,
theme: const NeumorphicThemeData(
baseColor: Color(0xFFE0E0E0),
lightSource: LightSource.topLeft,
depth: 10,
),
home: HomePage(),
)
// 新拟态按钮
NeumorphicButton(
onPressed: () {},
style: const NeumorphicStyle(
shape: NeumorphicShape.flat,
boxShape: NeumorphicBoxShape.roundRect(
BorderRadius.all(Radius.circular(12)),
),
),
child: const Text('按钮'),
)
// 新拟态容器
Neumorphic(
style: const NeumorphicStyle(
depth: 8,
intensity: 0.65,
),
child: Container(
width: 200,
height: 100,
child: const Center(child: Text('新拟态卡片')),
),
)
// 新拟态图标
NeumorphicIcon(
Icons.favorite,
size: 60,
style: const NeumorphicStyle(color: Colors.red),
)
// 新拟态进度条
NeumorphicProgress(
percent: 0.7,
height: 20,
style: const ProgressStyle(
accent: Colors.blue,
variant: Colors.blueGrey,
),
)
fluent_ui(微软 Fluent 风格)
Windows 风格的 UI 组件。
dependencies:
fluent_ui: ^4.8.5
import 'package:fluent_ui/fluent_ui.dart';
// 使用 FluentApp
FluentApp(
title: 'Fluent App',
theme: FluentThemeData(
accentColor: Colors.blue,
brightness: Brightness.light,
),
home: const HomePage(),
)
// Fluent 按钮
FilledButton(
child: const Text('填充按钮'),
onPressed: () {},
)
Button(
child: const Text('普通按钮'),
onPressed: () {},
)
// 导航视图
NavigationView(
appBar: const NavigationAppBar(
title: Text('Fluent App'),
),
pane: NavigationPane(
selected: selectedIndex,
onChanged: (index) => setState(() => selectedIndex = index),
displayMode: PaneDisplayMode.auto,
items: [
PaneItem(
icon: const Icon(FluentIcons.home),
title: const Text('首页'),
body: const HomePage(),
),
PaneItem(
icon: const Icon(FluentIcons.settings),
title: const Text('设置'),
body: const SettingsPage(),
),
],
),
)
// 信息栏
InfoBar(
title: const Text('提示'),
content: const Text('这是一条提示信息'),
severity: InfoBarSeverity.info, // info, warning, error, success
onClose: () {},
)
macos_ui(苹果 macOS 风格)
macOS 风格的 UI 组件,适合开发 macOS 应用。
dependencies:
macos_ui: ^2.0.5
import 'package:macos_ui/macos_ui.dart';
// 使用 MacosApp
MacosApp(
title: 'macOS App',
theme: MacosThemeData.light(),
darkTheme: MacosThemeData.dark(),
home: const MainPage(),
)
// macOS 窗口
MacosWindow(
sidebar: Sidebar(
builder: (context, scrollController) {
return SidebarItems(
items: [
SidebarItem(
leading: const MacosIcon(CupertinoIcons.home),
label: const Text('首页'),
),
SidebarItem(
leading: const MacosIcon(CupertinoIcons.settings),
label: const Text('设置'),
),
],
currentIndex: selectedIndex,
onChanged: (index) => setState(() => selectedIndex = index),
);
},
minWidth: 200,
),
child: ContentArea(
builder: (context, scrollController) {
return pages[selectedIndex];
},
),
)
// macOS 按钮
PushButton(
buttonSize: ButtonSize.large,
child: const Text('按钮'),
onPressed: () {},
)
📊 图表库
fl_chart(推荐)
功能强大、高度可定制的图表库。
dependencies:
fl_chart: ^0.66.2
import 'package:fl_chart/fl_chart.dart';
// 折线图
LineChart(
LineChartData(
gridData: const FlGridData(show: true),
titlesData: const FlTitlesData(show: true),
borderData: FlBorderData(show: true),
lineBarsData: [
LineChartBarData(
spots: const [
FlSpot(0, 3),
FlSpot(1, 1),
FlSpot(2, 4),
FlSpot(3, 2),
FlSpot(4, 5),
],
isCurved: true,
color: Colors.blue,
barWidth: 3,
dotData: const FlDotData(show: true),
belowBarData: BarAreaData(
show: true,
color: Colors.blue.withOpacity(0.3),
),
),
],
),
)
// 柱状图
BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
maxY: 20,
barGroups: [
BarChartGroupData(x: 0, barRods: [
BarChartRodData(toY: 8, color: Colors.blue),
]),
BarChartGroupData(x: 1, barRods: [
BarChartRodData(toY: 12, color: Colors.blue),
]),
BarChartGroupData(x: 2, barRods: [
BarChartRodData(toY: 6, color: Colors.blue),
]),
BarChartGroupData(x: 3, barRods: [
BarChartRodData(toY: 15, color: Colors.blue),
]),
],
),
)
// 饼图
PieChart(
PieChartData(
sections: [
PieChartSectionData(
value: 40,
title: '40%',
color: Colors.blue,
radius: 50,
),
PieChartSectionData(
value: 30,
title: '30%',
color: Colors.green,
radius: 50,
),
PieChartSectionData(
value: 30,
title: '30%',
color: Colors.orange,
radius: 50,
),
],
centerSpaceRadius: 40,
),
)
// 雷达图
RadarChart(
RadarChartData(
radarShape: RadarShape.polygon,
tickCount: 5,
ticksTextStyle: const TextStyle(color: Colors.transparent),
radarBorderData: const BorderSide(color: Colors.grey),
dataSets: [
RadarDataSet(
fillColor: Colors.blue.withOpacity(0.3),
borderColor: Colors.blue,
dataEntries: const [
RadarEntry(value: 4),
RadarEntry(value: 3),
RadarEntry(value: 5),
RadarEntry(value: 2),
RadarEntry(value: 4),
],
),
],
),
)
syncfusion_flutter_charts(企业级)
Syncfusion 出品,功能非常全面(社区版免费)。
dependencies:
syncfusion_flutter_charts: ^24.2.7
import 'package:syncfusion_flutter_charts/charts.dart';
// 折线图
SfCartesianChart(
primaryXAxis: const CategoryAxis(),
series: <LineSeries<SalesData, String>>[
LineSeries<SalesData, String>(
dataSource: [
SalesData('一月', 35),
SalesData('二月', 28),
SalesData('三月', 34),
SalesData('四月', 32),
SalesData('五月', 40),
],
xValueMapper: (data, _) => data.month,
yValueMapper: (data, _) => data.sales,
name: '销售额',
markerSettings: const MarkerSettings(isVisible: true),
)
],
)
class SalesData {
final String month;
final double sales;
SalesData(this.month, this.sales);
}
// 环形图
SfCircularChart(
legend: const Legend(isVisible: true),
series: <CircularSeries>[
DoughnutSeries<ChartData, String>(
dataSource: chartData,
xValueMapper: (data, _) => data.category,
yValueMapper: (data, _) => data.value,
dataLabelSettings: const DataLabelSettings(isVisible: true),
)
],
)
✨ 动画库
flutter_animate(推荐)
最简单易用的动画库。
dependencies:
flutter_animate: ^4.5.0
import 'package:flutter_animate/flutter_animate.dart';
// 基本动画
Text('Hello')
.animate()
.fadeIn(duration: 500.ms)
.slideY(begin: 0.3, end: 0)
// 链式动画
Container()
.animate()
.fade(duration: 300.ms)
.scale(delay: 300.ms)
.move(delay: 600.ms, duration: 300.ms)
// 循环动画
Icon(Icons.favorite)
.animate(onPlay: (controller) => controller.repeat())
.scale(begin: const Offset(1, 1), end: const Offset(1.2, 1.2))
.then()
.scale(begin: const Offset(1.2, 1.2), end: const Offset(1, 1))
// 列表动画
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: Text(items[index]))
.animate()
.fadeIn(delay: (100 * index).ms)
.slideX(begin: 0.5, end: 0);
},
)
// 交互动画
ElevatedButton(
onPressed: () {},
child: const Text('按钮'),
)
.animate(target: isHovered ? 1 : 0)
.scale(begin: const Offset(1, 1), end: const Offset(1.1, 1.1))
lottie(JSON 动画)
播放 Lottie JSON 动画文件。
dependencies:
lottie: ^3.1.0
import 'package:lottie/lottie.dart';
// 从 assets 加载
Lottie.asset(
'assets/animations/loading.json',
width: 200,
height: 200,
fit: BoxFit.contain,
)
// 从网络加载
Lottie.network(
'https://assets.lottiefiles.com/packages/xxx.json',
width: 200,
height: 200,
)
// 控制动画
class LottieExample extends StatefulWidget {
State<LottieExample> createState() => _LottieExampleState();
}
class _LottieExampleState extends State<LottieExample>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
void dispose() {
_controller.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Column(
children: [
Lottie.asset(
'assets/animations/heart.json',
controller: _controller,
onLoaded: (composition) {
_controller.duration = composition.duration;
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: () => _controller.forward(),
),
IconButton(
icon: const Icon(Icons.pause),
onPressed: () => _controller.stop(),
),
IconButton(
icon: const Icon(Icons.replay),
onPressed: () => _controller.reset(),
),
],
),
],
);
}
}
获取 Lottie 动画资源:
- LottieFiles - 最大的 Lottie 动画库
- Icons8 - 动画图标
rive(高级交互动画)
支持复杂交互的动画引擎。
dependencies:
rive: ^0.13.2
import 'package:rive/rive.dart';
// 基本使用
RiveAnimation.asset(
'assets/animations/example.riv',
fit: BoxFit.cover,
)
// 带状态机控制
class RiveExample extends StatefulWidget {
State<RiveExample> createState() => _RiveExampleState();
}
class _RiveExampleState extends State<RiveExample> {
SMITrigger? _trigger;
void _onRiveInit(Artboard artboard) {
final controller = StateMachineController.fromArtboard(artboard, 'State Machine 1');
if (controller != null) {
artboard.addController(controller);
_trigger = controller.findInput<bool>('trigger') as SMITrigger?;
}
}
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _trigger?.fire(),
child: RiveAnimation.asset(
'assets/animations/interactive.riv',
onInit: _onRiveInit,
),
);
}
}
获取 Rive 动画:
- Rive Community - Rive 社区资源
🎯 图标库
font_awesome_flutter
最流行的图标库 Font Awesome。
dependencies:
font_awesome_flutter: ^10.7.0
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
// 实心图标
FaIcon(FontAwesomeIcons.solidHeart, color: Colors.red)
// 常规图标
FaIcon(FontAwesomeIcons.heart)
// 品牌图标
FaIcon(FontAwesomeIcons.github)
FaIcon(FontAwesomeIcons.twitter)
FaIcon(FontAwesomeIcons.weixin)
// 带大小
FaIcon(FontAwesomeIcons.star, size: 30)
line_icons
Line Icons 风格图标。
dependencies:
line_icons: ^2.0.3
import 'package:line_icons/line_icons.dart';
Icon(LineIcons.home)
Icon(LineIcons.user)
Icon(LineIcons.cog)
Icon(LineIcons.heart)
Icon(LineIcons.search)
// 或使用常量类
Icon(LineIcons.values[LineIcons.home])
iconsax_flutter
现代简约风格图标。
dependencies:
iconsax_flutter: ^1.0.0
import 'package:iconsax_flutter/iconsax_flutter.dart';
Icon(Iconsax.home)
Icon(Iconsax.user)
Icon(Iconsax.setting)
Icon(Iconsax.heart)
Icon(Iconsax.notification)
// 带样式
Icon(Iconsax.home_1) // 变体
Icon(Iconsax.home_2) // 另一个变体
自定义图标(iconfont)
使用阿里巴巴 iconfont 的自定义图标:
- 在 iconfont.cn 选择图标,下载字体文件
- 将
.ttf文件放到assets/fonts/目录 - 在
pubspec.yaml中配置:
flutter:
fonts:
- family: MyIcons
fonts:
- asset: assets/fonts/iconfont.ttf
- 创建图标类:
class MyIcons {
static const IconData home = IconData(0xe600, fontFamily: 'MyIcons');
static const IconData user = IconData(0xe601, fontFamily: 'MyIcons');
static const IconData settings = IconData(0xe602, fontFamily: 'MyIcons');
}
// 使用
Icon(MyIcons.home)
🎁 UI 资源推荐
设计资源
| 资源 | 说明 | 链接 |
|---|---|---|
| Dribbble | 设计灵感 | dribbble.com |
| Behance | 设计作品 | behance.net |
| Mobbin | App 设计参考 | mobbin.com |
| Figma Community | 免费设计模板 | figma.com/community |
Flutter UI 模板
| 项目 | 说明 | GitHub |
|---|---|---|
| FlutterExampleApps | 完整 App 示例 | github.com/iampawan/FlutterExampleApps |
| Best-Flutter-UI-Templates | 精美 UI 模板 | github.com/mitesh77/Best-Flutter-UI-Templates |
| flutter-ui-nice | UI 设计示例 | github.com/nickmilo/flutter-ui-nice |
颜色工具
| 工具 | 说明 | 链接 |
|---|---|---|
| Coolors | 配色生成器 | coolors.co |
| Color Hunt | 配色方案 | colorhunt.co |
| Material Color Tool | Material 配色 | material.io/resources/color |
📝 小结
这一章我们介绍了丰富的 UI 资源:
| 分类 | 推荐 | 特点 |
|---|---|---|
| 内置组件 | Material 3 | 官方支持,最稳定 |
| UI 框架 | GetWidget | 组件最全面 |
| 图表 | fl_chart | 高度可定制 |
| 动画 | flutter_animate, lottie | 简单易用 |
| 图标 | font_awesome_flutter | 最流行 |
UI 开发建议
- 先熟练内置组件 - Material 组件已经很丰富
- 按需引入第三方库 - 不要盲目引入太多包
- 保持风格统一 - 不要混用多种 UI 框架
- 多看优秀设计 - 提升审美能力
- 善用设计工具 - 配色、图标等工具
💪 练习题
- 使用 Material 3 组件构建一个设置页面
- 使用 GetWidget 创建一个卡片列表
- 使用 fl_chart 实现一个简单的数据统计页面
- 使用 flutter_animate 为列表添加入场动画
🚀 下一步
掌握了 UI 框架和组件库后,你可以前往 第15章 - 状态管理进阶,学习更强大的状态管理方案!
由 编程指南 提供
