Flutter中如何实现点击AppBar展开日历(仿谷歌日历效果)
实现点击AppBar展开日历面板的效果
要复现谷歌日历中点击AppBar展开日历的交互,核心是通过状态变量控制展开/收起状态,动态切换AppBar的样式(颜色、高度)并配合动画显示/隐藏日历面板。以下是具体实现方案:
核心思路
- 用布尔状态
isExpanded标记展开状态,点击AppBar时切换该状态 - 自定义AppBar,根据状态动态修改背景色、文字/图标颜色
- 使用
AnimatedContainer实现平滑的日历面板展开/收起动画 - 让AppBar样式变化与日历面板显示状态完全联动
完整代码示例
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Calendar Expand Demo', theme: ThemeData(primarySwatch: Colors.blue), home: const CalendarExpandPage(), ); } } class CalendarExpandPage extends StatefulWidget { const CalendarExpandPage({super.key}); @override State<CalendarExpandPage> createState() => _CalendarExpandPageState(); } class _CalendarExpandPageState extends State<CalendarExpandPage> { bool _isExpanded = false; // 切换展开/收起状态 void _toggleExpand() { setState(() { _isExpanded = !_isExpanded; }); } @override Widget build(BuildContext context) { return Scaffold( // 自定义可点击的AppBar appBar: PreferredSize( preferredSize: const Size.fromHeight(60), child: GestureDetector( onTap: _toggleExpand, child: Container( color: _isExpanded ? Colors.blue[700] : Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16), alignment: Alignment.centerLeft, child: Row( children: [ Icon( _isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down, color: _isExpanded ? Colors.white : Colors.black, ), const SizedBox(width: 8), Text( '2024年6月', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w500, color: _isExpanded ? Colors.white : Colors.black, ), ), ], ), ), ), ), body: Column( children: [ // 带动画的日历面板 AnimatedContainer( duration: const Duration(milliseconds: 300), height: _isExpanded ? 300 : 0, child: _isExpanded ? CalendarDatePicker( initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), onDateChanged: (date) {}, ) : null, ), // 页面主体内容 Expanded( child: Container( alignment: Alignment.center, child: const Text('主内容区域'), ), ), ], ), ); } }
关键细节说明
- 可点击AppBar:通过
GestureDetector包裹整个AppBar区域,实现点击任意位置触发状态切换;根据_isExpanded动态修改背景色和文字/图标颜色,解决你提到的AppBar颜色同步变化问题。 - 平滑动画:
AnimatedContainer自动处理高度从0到300的过渡动画,替代滑动触发的SliverAppBar逻辑,完全通过点击控制。 - 日历组件:示例使用Flutter自带的
CalendarDatePicker,你可以替换为第三方日历组件(如table_calendar)来实现更贴近谷歌日历的样式。 - 状态同步:所有UI变化(AppBar颜色、日历面板显示)都由
_isExpanded状态驱动,确保交互一致性。
扩展优化
- 如果需要保留AppBar的原生导航功能(返回按钮、右侧操作按钮),可以用
AppBar组件替代Container,示例如下:child: AppBar( backgroundColor: _isExpanded ? Colors.blue[700] : Colors.white, leading: const BackButton(color: Colors.black), title: Text('2024年6月', style: TextStyle(color: _isExpanded ? Colors.white : Colors.black)), actions: [IconButton(icon: const Icon(Icons.search), onPressed: () {})], automaticallyImplyLeading: true, ), - 可添加AppBar底部阴影,当展开日历面板时显示阴影,增强界面层次感。
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

