第一次接触Flutter的开发者可能会被AppBar的各种属性搞得晕头转向,但其实它的核心功能非常简单 - 就是创建一个顶部导航栏。我刚开始用Flutter时也犯过不少错误,比如把整个AppBar的背景色设置成透明结果完全看不见了。下面我们就从最基础的用法开始,一步步拆解这个看似简单实则强大的组件。
最基础的AppBar只需要一个title属性就能工作:
dart复制Scaffold(
appBar: AppBar(
title: Text('我的第一个AppBar'),
),
body: Center(child: Text('页面内容')),
);
这个简单的代码就能生成一个带有蓝色背景(Material Design默认主题色)和白色文字的导航栏。但实际开发中我们往往需要更多定制化功能,这时候就需要了解AppBar的三剑客:leading、title和actions。
leading是导航栏左侧的控件,通常用于返回按钮。如果不设置,在存在上级页面时会自动显示返回箭头。我遇到过需要自定义leading的情况,比如在一个电商App中,我们可能想把返回按钮换成店铺logo:
dart复制leading: IconButton(
icon: Image.asset('assets/store_logo.png'),
onPressed: () => Navigator.pop(context),
),
title不必多说,就是中间显示的标题。但有个小技巧:如果你想让标题在滑动时产生特殊效果,可以试试SliverAppBar,这个我们后面会详细讲解。
actions是我最喜欢的功能之一,它让右侧菜单变得非常简单。记得第一次实现搜索功能时,我傻傻地在body里自己布局,后来发现用actions只需要几行代码:
dart复制actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () => showSearch(context: context, delegate: MySearchDelegate()),
),
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(child: Text('设置')),
PopupMenuItem(child: Text('关于')),
],
)
],
当你的App需要独特的视觉风格时,AppBar的样式定制能力就派上用场了。去年我接手一个时尚电商项目,设计师要求导航栏要有渐变背景、自定义字体和特殊图标效果,这些全靠AppBar丰富的样式属性实现了。
背景色与前景色是最基础的样式设置。backgroundColor控制背景,foregroundColor影响标题和图标颜色。但有个坑我踩过:如果同时设置iconTheme和foregroundColor,后者会覆盖前者。所以最佳实践是:
dart复制AppBar(
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.white), // 保持一致性
actionsIconTheme: IconThemeData(color: Colors.white),
)
阴影效果可以通过elevation和shadowColor控制。Material Design建议不同层级的组件使用不同的elevation值:
| Elevation值 | 适用场景 |
|---|---|
| 0 | 无阴影的平面组件 |
| 4 | 默认AppBar高度 |
| 8 | 悬浮按钮 |
| 16 | 对话框 |
形状定制是很多人忽略的功能。通过shape属性,你可以做出圆角、切口等特殊效果:
dart复制shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(20),
),
),
文字样式的定制需要注意主题继承问题。titleTextStyle会覆盖主题中的样式,但如果你想要全局统一的标题样式,最好在ThemeData中设置:
dart复制ThemeData(
appBarTheme: AppBarTheme(
titleTextStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
fontFamily: 'CustomFont',
),
),
)
静态的导航栏已经不能满足现代App的需求了。通过一些高级技巧,我们可以让AppBar根据用户操作产生动态变化。去年开发社交App时,我实现了滚动隐藏、搜索框展开等效果,用户反馈特别好。
滚动控制是最常见的交互需求。使用SliverAppBar配合CustomScrollView可以实现丰富的滚动效果:
dart复制CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('动态标题'),
background: Image.network('header.jpg', fit: BoxFit.cover),
),
),
SliverList(...),
],
)
这个代码实现了:
动态主题切换是另一个实用技巧。比如实现深色模式时,AppBar需要同步切换:
dart复制AppBar(
backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
systemOverlayStyle: Theme.of(context).appBarTheme.systemOverlayStyle,
)
搜索栏转换是我在电商项目中实现的另一个效果:点击搜索图标后,整个AppBar变成搜索框:
dart复制bool isSearching = false;
AppBar(
title: isSearching
? TextField(autofocus: true, decoration: InputDecoration(hintText: '搜索...'))
: Text('商品列表'),
actions: [
IconButton(
icon: Icon(isSearching ? Icons.close : Icons.search),
onPressed: () => setState(() => isSearching = !isSearching),
),
],
)
现在我们把所有知识综合起来,实现一个完整的电商App导航栏。这个案例包含logo、搜索框、购物车图标和消息提醒等真实功能。
基础结构搭建如下:
dart复制AppBar(
leading: Padding(
padding: EdgeInsets.all(8),
child: Image.asset('assets/logo.png'),
),
title: Container(
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
border: InputBorder.none,
hintText: '搜索商品...',
),
),
),
actions: [
Stack(
children: [
IconButton(icon: Icon(Icons.shopping_cart), onPressed: () {}),
Positioned(
right: 8,
top: 8,
child: Container(
padding: EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Text('3', style: TextStyle(fontSize: 10)),
),
)
],
),
// 类似的消息图标
],
)
状态管理是实际开发中的关键。我推荐使用Provider或Riverpod来管理购物车数量等状态:
dart复制final cartCount = Provider<int>((ref) => 0);
// 在组件中
Consumer(builder: (context, ref, _) {
final count = ref.watch(cartCount);
return Badge(count: count, child: Icon(Icons.shopping_cart));
})
性能优化也很重要。避免在AppBar中使用复杂的布局和频繁重建的组件。我曾经因为在一个AppBar里放了动画导致页面卡顿,后来通过将动画移到底层解决了这个问题。
多平台适配是最后的考虑点。在iOS上,你可能需要调整标题位置和返回按钮样式:
dart复制appBarTheme: AppBarTheme(
centerTitle: Platform.isIOS,
toolbarHeight: Platform.isIOS ? 44 : 56,
)