基础入门 Flutter for OpenHarmony:FloatingActionButton 浮动按钮详解
在 Flutter for OpenHarmony 应用开发中,FloatingActionButton(浮动按钮,简称 FAB)是一种悬浮在页面内容之上的圆形按钮,用于表示页面最主要的操作。它是 Material Design 设计语言中最具标志性的组件之一,通常放置在屏幕右下角,点击时会触发页面的主要操作。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
🎯 欢迎来到 Flutter for OpenHarmony 社区!本文将深入讲解 Flutter 中 FloatingActionButton 浮动按钮的使用方法,带你从基础到精通,掌握这一 Material Design 标志性的交互组件。
一、FloatingActionButton 组件概述
在 Flutter for OpenHarmony 应用开发中,FloatingActionButton(浮动按钮,简称 FAB)是一种悬浮在页面内容之上的圆形按钮,用于表示页面最主要的操作。它是 Material Design 设计语言中最具标志性的组件之一,通常放置在屏幕右下角,点击时会触发页面的主要操作。
📋 FloatingActionButton 类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
| 标准 FAB | 56x56dp 的圆形按钮 | 单一主要操作 |
| 小型 FAB | 40x40dp 的圆形按钮 | 空间受限时 |
| 大型 FAB | 96x96dp 的圆形按钮 | 需要突出显示 |
| 扩展 FAB | 带文字的宽按钮 | 需要文字说明 |
| 速度拨 FAB | 展开多个子按钮 | 多个相关操作 |
💡 使用场景:FloatingActionButton 常用于新建、编辑、添加、分享、导航等页面的主要操作。
二、FloatingActionButton 基础用法
FloatingActionButton 通常作为 Scaffold 的 floatingActionButton 属性使用。
2.1 最简单的 FloatingActionButton
Scaffold(
appBar: AppBar(title: const Text('FAB 示例')),
floatingActionButton: FloatingActionButton(
onPressed: () {
print('FAB 被点击');
},
child: const Icon(Icons.add),
),
body: const Center(
child: Text('点击右下角的浮动按钮'),
),
)
代码解析:
onPressed:点击回调,设为null时按钮禁用child:按钮内显示的内容,通常是 Icon
2.2 完整示例
下面是一个完整的可运行示例,展示 FloatingActionButton 的基本使用:
class FabExample extends StatefulWidget {
const FabExample({super.key});
State<FabExample> createState() => _FabExampleState();
}
class _FabExampleState extends State<FabExample> {
int _counter = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('FloatingActionButton 示例')),
body: Center(
child: Text(
'计数器: $_counter',
style: const TextStyle(fontSize: 32),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: const Icon(Icons.add),
),
);
}
}
三、FloatingActionButton 常用属性
3.1 onPressed - 点击回调
设置按钮的点击事件,设为 null 时按钮禁用。
FloatingActionButton(
onPressed: () {
// 执行操作
},
child: const Icon(Icons.add),
)
FloatingActionButton(
onPressed: null, // 禁用状态
child: const Icon(Icons.add),
)
3.2 child - 子组件
设置按钮内显示的内容,通常是图标。
FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.edit),
)
FloatingActionButton(
onPressed: () {},
child: const Text('添加'),
)
3.3 backgroundColor - 背景颜色
设置按钮的背景颜色。
FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.blue,
child: const Icon(Icons.add),
)
3.4 foregroundColor - 前景颜色
设置按钮内图标/文字的颜色。
FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
child: const Icon(Icons.add),
)
3.5 heroTag - Hero 动画标签
用于页面切换时的 Hero 动画标识,多个 FAB 需要设置不同的 heroTag。
FloatingActionButton(
onPressed: () {},
heroTag: 'fab_1',
child: const Icon(Icons.add),
)
3.6 mini - 小型按钮
设置为 true 时显示小型 FAB(40x40dp)。
FloatingActionButton(
onPressed: () {},
mini: true,
child: const Icon(Icons.add),
)
3.7 shape - 形状
设置按钮的形状。
FloatingActionButton(
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: const Icon(Icons.add),
)
3.8 elevation - 阴影高度
设置按钮的阴影高度。
FloatingActionButton(
onPressed: () {},
elevation: 12,
child: const Icon(Icons.add),
)
3.9 highlightElevation - 按下时阴影
设置按钮按下时的阴影高度。
FloatingActionButton(
onPressed: () {},
elevation: 6,
highlightElevation: 12,
child: const Icon(Icons.add),
)
3.10 tooltip - 长按提示
设置长按时显示的提示文字。
FloatingActionButton(
onPressed: () {},
tooltip: '添加新项目',
child: const Icon(Icons.add),
)
📊 FloatingActionButton 属性速查表
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
onPressed |
VoidCallback? | - | 点击回调 |
child |
Widget? | - | 子组件 |
backgroundColor |
Color? | - | 背景颜色 |
foregroundColor |
Color? | - | 前景颜色 |
heroTag |
Object? | - | Hero 动画标签 |
mini |
bool | false | 是否小型 |
shape |
ShapeBorder? | CircleBorder | 形状 |
elevation |
double? | 6 | 阴影高度 |
highlightElevation |
double? | 12 | 按下时阴影 |
tooltip |
String? | - | 长按提示 |
四、FloatingActionButton 位置控制
4.1 floatingActionButtonLocation
通过 Scaffold 的 floatingActionButtonLocation 属性控制 FAB 的位置。
Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
)
常用位置:
| 位置 | 说明 |
|---|---|
FloatingActionButtonLocation.endFloat |
右下角浮动(默认) |
FloatingActionButtonLocation.centerFloat |
底部居中浮动 |
FloatingActionButtonLocation.startFloat |
左下角浮动 |
FloatingActionButtonLocation.endDocked |
右下角停靠 |
FloatingActionButtonLocation.centerDocked |
底部居中停靠 |
FloatingActionButtonLocation.startDocked |
左下角停靠 |
FloatingActionButtonLocation.endTop |
右上角 |
FloatingActionButtonLocation.startTop |
左上角 |
4.2 自定义位置
class CustomFabLocation extends FloatingActionButtonLocation {
final double offsetX;
final double offsetY;
CustomFabLocation({required this.offsetX, required this.offsetY});
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
return Offset(offsetX, offsetY);
}
}
Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: CustomFabLocation(offsetX: 100, offsetY: 200),
)
五、FloatingActionButton 扩展类型
5.1 FloatingActionButton.extended - 扩展 FAB
带有图标和文字的宽按钮。
FloatingActionButton.extended(
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('添加'),
)
扩展 FAB 属性:
| 属性 | 类型 | 说明 |
|---|---|---|
icon |
Widget? | 图标 |
label |
Widget | 文字标签 |
extendedTextStyle |
TextStyle? | 文字样式 |
extendedIconLabelSpacing |
double? | 图标与文字间距 |
extendedPadding |
EdgeInsetsGeometry? | 内边距 |
5.2 FloatingActionButton.large - 大型 FAB
更大的浮动按钮(96x96dp)。
FloatingActionButton.large(
onPressed: () {},
child: const Icon(Icons.add),
)
5.3 FloatingActionButton.small - 小型 FAB
更小的浮动按钮(40x40dp)。
FloatingActionButton.small(
onPressed: () {},
child: const Icon(Icons.add),
)
六、FloatingActionButton 与 BottomAppBar 配合
FloatingActionButton 可以与 BottomAppBar 配合,创建凹槽效果。
6.1 基本配合
Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
shape: const CircularNotchedRectangle(),
notchMargin: 8,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: const Icon(Icons.home),
onPressed: () {},
),
const SizedBox(width: 48),
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {},
),
],
),
),
)
6.2 完整底部导航示例
class BottomAppBarDemo extends StatefulWidget {
const BottomAppBarDemo({super.key});
State<BottomAppBarDemo> createState() => _BottomAppBarDemoState();
}
class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
int _selectedIndex = 0;
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('页面 $_selectedIndex'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('FAB 被点击')),
);
},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
shape: const CircularNotchedRectangle(),
notchMargin: 8,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(
Icons.home,
color: _selectedIndex == 0 ? Colors.blue : Colors.grey,
),
onPressed: () => setState(() => _selectedIndex = 0),
),
IconButton(
icon: Icon(
Icons.search,
color: _selectedIndex == 1 ? Colors.blue : Colors.grey,
),
onPressed: () => setState(() => _selectedIndex = 1),
),
const SizedBox(width: 48),
IconButton(
icon: Icon(
Icons.favorite,
color: _selectedIndex == 2 ? Colors.blue : Colors.grey,
),
onPressed: () => setState(() => _selectedIndex = 2),
),
IconButton(
icon: Icon(
Icons.person,
color: _selectedIndex == 3 ? Colors.blue : Colors.grey,
),
onPressed: () => setState(() => _selectedIndex = 3),
),
],
),
),
);
}
}
七、SpeedDial 速度拨按钮
当需要多个相关操作时,可以使用展开式的 SpeedDial 按钮。
7.1 实现方式
class SpeedDialDemo extends StatefulWidget {
const SpeedDialDemo({super.key});
State<SpeedDialDemo> createState() => _SpeedDialDemoState();
}
class _SpeedDialDemoState extends State<SpeedDialDemo> {
bool _isExpanded = false;
void _toggleExpanded() {
setState(() {
_isExpanded = !_isExpanded;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('SpeedDial 示例')),
body: const Center(
child: Text('点击右下角的浮动按钮'),
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_isExpanded) ...[
_buildSpeedDialItem(Icons.email, '邮件', Colors.blue, () {}),
const SizedBox(height: 12),
_buildSpeedDialItem(Icons.message, '消息', Colors.green, () {}),
const SizedBox(height: 12),
_buildSpeedDialItem(Icons.share, '分享', Colors.orange, () {}),
const SizedBox(height: 12),
],
FloatingActionButton(
onPressed: _toggleExpanded,
child: AnimatedRotation(
turns: _isExpanded ? 0.125 : 0,
duration: const Duration(milliseconds: 200),
child: const Icon(Icons.add),
),
),
],
),
);
}
Widget _buildSpeedDialItem(
IconData icon,
String label,
Color color,
VoidCallback onTap,
) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(4),
),
child: Text(
label,
style: const TextStyle(color: Colors.white),
),
),
const SizedBox(width: 12),
FloatingActionButton.small(
heroTag: label,
backgroundColor: color,
onPressed: () {
_toggleExpanded();
onTap();
},
child: Icon(icon),
),
],
);
}
}
八、实际应用场景
8.1 列表添加操作
class ListWithFab extends StatefulWidget {
const ListWithFab({super.key});
State<ListWithFab> createState() => _ListWithFabState();
}
class _ListWithFabState extends State<ListWithFab> {
final List<String> _items = [];
void _addItem() {
setState(() {
_items.add('项目 ${_items.length + 1}');
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('列表')),
body: _items.isEmpty
? const Center(child: Text('点击 + 添加项目'))
: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_items[index]),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
_items.removeAt(index);
});
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addItem,
child: const Icon(Icons.add),
),
);
}
}
8.2 编辑操作
class EditPage extends StatelessWidget {
const EditPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('编辑')),
body: const Padding(
padding: EdgeInsets.all(16),
child: TextField(
maxLines: 10,
decoration: InputDecoration(
hintText: '输入内容...',
border: OutlineInputBorder(),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已保存')),
);
},
child: const Icon(Icons.save),
),
);
}
}
8.3 导航操作
class NavigationPage extends StatelessWidget {
const NavigationPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('导航')),
body: const Center(
child: Text('点击按钮跳转到下一页'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NextPage()),
);
},
child: const Icon(Icons.arrow_forward),
),
);
}
}
class NextPage extends StatelessWidget {
const NextPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('下一页')),
body: const Center(child: Text('这是下一页')),
);
}
}
8.4 分享操作
class SharePage extends StatelessWidget {
const SharePage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('分享')),
body: const Center(
child: Text('点击按钮分享内容'),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.chat),
title: const Text('微信'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.message),
title: const Text('短信'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.email),
title: const Text('邮件'),
onTap: () => Navigator.pop(context),
),
],
),
);
},
);
},
icon: const Icon(Icons.share),
label: const Text('分享'),
),
);
}
}
九、完整示例代码
下面是一个完整的 Flutter 应用示例,展示 FloatingActionButton 组件的各种用法。
import 'package:flutter/material.dart';
void main() {
runApp(const FloatingActionButtonDemo());
}
class FloatingActionButtonDemo extends StatelessWidget {
const FloatingActionButtonDemo({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'FloatingActionButton 组件演示',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.light(
primary: const Color(0xFF6366F1),
secondary: const Color(0xFF8B5CF6),
surface: const Color(0xFFE8EAF6),
background: const Color(0xFFF8F9FF),
brightness: Brightness.light,
),
useMaterial3: true,
),
home: const FloatingActionButtonPage(),
);
}
}
class FloatingActionButtonPage extends StatefulWidget {
const FloatingActionButtonPage({super.key});
State<FloatingActionButtonPage> createState() => _FloatingActionButtonPageState();
}
class _FloatingActionButtonPageState extends State<FloatingActionButtonPage> {
int _counter = 0;
int _selectedTab = 0;
bool _speedDialExpanded = false;
final List<String> _items = [];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('FloatingActionButton 组件演示'),
centerTitle: true,
elevation: 0,
),
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFE8F4FF),
Color(0xFFF8F9FF),
],
),
),
child: SafeArea(
child: _buildBody(),
),
),
floatingActionButton: _buildFab(),
floatingActionButtonLocation: _selectedTab == 2
? FloatingActionButtonLocation.centerFloat
: FloatingActionButtonLocation.endFloat,
bottomNavigationBar: _selectedTab == 3
? null
: BottomNavigationBar(
currentIndex: _selectedTab,
onTap: (index) => setState(() => _selectedTab = index),
selectedItemColor: const Color(0xFF6366F1),
unselectedItemColor: Colors.grey,
backgroundColor: Colors.white,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '基础',
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: '列表',
),
BottomNavigationBarItem(
icon: Icon(Icons.edit),
label: '扩展',
),
BottomNavigationBarItem(
icon: Icon(Icons.more),
label: '速度拨',
),
],
),
);
}
Widget _buildBody() {
switch (_selectedTab) {
case 0:
return _buildBasicTab();
case 1:
return _buildListTab();
case 2:
return _buildExtendedTab();
case 3:
return _buildSpeedDialTab();
default:
return _buildBasicTab();
}
}
Widget _buildBasicTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildHeader(),
const SizedBox(height: 24),
_buildCounterCard(),
const SizedBox(height: 16),
_buildFabTypesCard(),
],
),
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF6366F1),
Color(0xFF8B5CF6),
Color(0xFFEC4899),
],
),
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: const Color(0xFF6366F1).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'🔘 FloatingActionButton',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 8),
Text(
'Material Design 标志性的浮动操作按钮',
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
],
),
);
}
Widget _buildCounterCard() {
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: Colors.grey.withOpacity(0.2)),
),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
const Text(
'计数器示例',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
Text(
'$_counter',
style: const TextStyle(
fontSize: 64,
fontWeight: FontWeight.bold,
color: Color(0xFF6366F1),
),
),
const SizedBox(height: 16),
const Text(
'点击右下角的 FAB 增加计数',
style: TextStyle(color: Colors.grey),
),
],
),
),
);
}
Widget _buildFabTypesCard() {
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: Colors.grey.withOpacity(0.2)),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'FAB 类型',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
FloatingActionButton.small(
heroTag: 'small',
onPressed: () {},
child: const Icon(Icons.add, size: 20),
),
const SizedBox(height: 8),
const Text('小型', style: TextStyle(fontSize: 12)),
],
),
Column(
children: [
FloatingActionButton(
heroTag: 'standard',
onPressed: () {},
child: const Icon(Icons.add),
),
const SizedBox(height: 8),
const Text('标准', style: TextStyle(fontSize: 12)),
],
),
Column(
children: [
FloatingActionButton.large(
heroTag: 'large',
onPressed: () {},
child: const Icon(Icons.add, size: 32),
),
const SizedBox(height: 8),
const Text('大型', style: TextStyle(fontSize: 12)),
],
),
],
),
],
),
),
);
}
Widget _buildListTab() {
return _items.isEmpty
? const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.inbox, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text(
'列表为空',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
SizedBox(height: 8),
Text(
'点击 FAB 添加项目',
style: TextStyle(color: Colors.grey),
),
],
),
)
: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: _items.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xFF6366F1),
child: Text('${index + 1}'),
),
title: Text(_items[index]),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () {
setState(() {
_items.removeAt(index);
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已删除')),
);
},
),
),
);
},
);
}
Widget _buildExtendedTab() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'扩展 FAB 示例',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 32),
FloatingActionButton.extended(
heroTag: 'extended1',
onPressed: () {},
icon: const Icon(Icons.add),
label: const Text('添加项目'),
),
const SizedBox(height: 16),
FloatingActionButton.extended(
heroTag: 'extended2',
onPressed: () {},
backgroundColor: Colors.green,
icon: const Icon(Icons.share),
label: const Text('分享'),
),
const SizedBox(height: 16),
FloatingActionButton.extended(
heroTag: 'extended3',
onPressed: () {},
backgroundColor: Colors.orange,
icon: const Icon(Icons.edit),
label: const Text('编辑'),
),
],
),
);
}
Widget _buildSpeedDialTab() {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.touch_app, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text(
'速度拨示例',
style: TextStyle(fontSize: 18, color: Colors.grey),
),
SizedBox(height: 8),
Text(
'点击 FAB 展开更多选项',
style: TextStyle(color: Colors.grey),
),
],
),
);
}
Widget _buildFab() {
if (_selectedTab == 3) {
return _buildSpeedDialFab();
}
if (_selectedTab == 2) {
return FloatingActionButton.extended(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('扩展 FAB 被点击')),
);
},
icon: const Icon(Icons.check),
label: const Text('保存'),
);
}
if (_selectedTab == 1) {
return FloatingActionButton(
onPressed: () {
setState(() {
_items.add('项目 ${_items.length + 1}');
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已添加')),
);
},
child: const Icon(Icons.add),
);
}
return FloatingActionButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: const Icon(Icons.add),
);
}
Widget _buildSpeedDialFab() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (_speedDialExpanded) ...[
_buildSpeedDialItem(
Icons.email,
'发送邮件',
Colors.blue,
),
const SizedBox(height: 12),
_buildSpeedDialItem(
Icons.message,
'发送消息',
Colors.green,
),
const SizedBox(height: 12),
_buildSpeedDialItem(
Icons.share,
'分享',
Colors.orange,
),
const SizedBox(height: 12),
],
FloatingActionButton(
onPressed: () {
setState(() {
_speedDialExpanded = !_speedDialExpanded;
});
},
child: AnimatedRotation(
turns: _speedDialExpanded ? 0.125 : 0,
duration: const Duration(milliseconds: 200),
child: const Icon(Icons.add),
),
),
],
);
}
Widget _buildSpeedDialItem(IconData icon, String label, Color color) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(4),
),
child: Text(
label,
style: const TextStyle(color: Colors.white),
),
),
const SizedBox(width: 12),
FloatingActionButton.small(
heroTag: label,
backgroundColor: color,
onPressed: () {
setState(() {
_speedDialExpanded = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('$label 被点击')),
);
},
child: Icon(icon),
),
],
);
}
}
十、总结
FloatingActionButton 是 Flutter for OpenHarmony 应用开发中 Material Design 风格的重要组件。通过本文的学习,我们掌握了:
- 基础用法:FloatingActionButton 的基本属性和使用方式
- 常用属性:onPressed、child、backgroundColor、mini 等
- 位置控制:floatingActionButtonLocation 的各种位置选项
- 扩展类型:extended、large、small 等不同尺寸的 FAB
- 配合使用:与 BottomAppBar 配合创建凹槽效果
- 速度拨按钮:展开式多操作按钮的实现
- 实际应用:列表添加、编辑保存、导航跳转、分享操作等场景
💡 开发建议:使用 FloatingActionButton 时应注意:
- 每个页面只使用一个主 FAB
- FAB 代表页面的最主要操作
- 合理选择 FAB 的尺寸和位置
- 使用 heroTag 避免页面切换时的动画冲突
- 配合 BottomAppBar 创建更丰富的底部导航
更多推荐

所有评论(0)