You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:51:00