Android Studio环境下使用Flutter实现日历Widget的方法与示例

实现方案
Flutter完全可以实现安卓主屏幕日历Widget,目前生态已经有成熟的落地路径,不需要从零手写平台层逻辑,下面是可直接复用的实现参考:
目前主流实现分两类:
- 快速实现:使用
home_widget插件,封装了Flutter和原生Widget的通信、渲染逻辑,90%以上的日历场景都能用这个方案搞定,稳定性足够 - 自定义实现:手写
MethodChannel对接安卓原生AppWidget框架,灵活度最高,适合需要复杂交互、动画的特殊场景,但是适配成本高
基于home_widget的日历Widget实现步骤
1. 配置依赖
在项目的pubspec.yaml中添加依赖:
dependencies: flutter: sdk: flutter home_widget: ^0.6.0 # 可以替换为pub上的最新稳定版本
2. 安卓端原生配置
首先在android/app/src/main/AndroidManifest.xml的<application>标签内注册Widget接收器:
<receiver android:name="io.flutter.plugins.homewidget.HomeWidgetReceiver" android:exported="true"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver>
接着在android/app/src/main/res下新建xml目录,创建widget_info.xml配置Widget的基础属性:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="250dp" android:minHeight="180dp" android:updatePeriodMillis="1800000" android:initialLayout="@layout/widget_initial" android:resizeMode="horizontal|vertical" android:widgetCategory="home_screen"> </appwidget-provider>
注意安卓系统对Widget的后台自动更新有强制限制,最短间隔为30分钟,日历类场景不需要依赖这个自动更新,在App内添加/修改日程、切换日期时主动触发刷新即可。
然后在res/layout目录下新建widget_initial.xml作为Widget加载前的占位布局:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="12dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="日历加载中..." /> </FrameLayout>
3. Flutter层代码实现
核心逻辑是把Flutter写的日历组件渲染为位图,同步给原生层展示,示例代码如下:
import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; // 和Manifest中注册的接收器类名保持一致 const String _widgetProviderName = 'HomeWidgetReceiver'; const String _widgetRenderKey = 'calendar_widget_view'; class CalendarHomePage extends StatefulWidget { const CalendarHomePage({super.key}); @override State<CalendarHomePage> createState() => _CalendarHomePageState(); } class _CalendarHomePageState extends State<CalendarHomePage> { @override void initState() { super.initState(); // App启动时主动刷新一次桌面Widget refreshDesktopCalendar(); } Future<void> refreshDesktopCalendar() async { // 这里写你的日历组件,和普通Flutter页面写法完全一致,可以加月视图、日期标记、日程红点等逻辑 final calendarView = RepaintBoundary( child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( '2024年6月', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), ), const SizedBox(height: 12), // 省略日历日期网格、日程标记的具体实现,按普通Flutter组件写即可 ], ), ), ); // 将Flutter组件渲染为位图同步给原生 await HomeWidget.renderFlutterWidget( calendarView, key: _widgetRenderKey, logicalSize: const Size(300, 220), // 匹配你配置的Widget实际显示尺寸 ); // 通知系统刷新桌面Widget await HomeWidget.updateWidget(androidName: _widgetProviderName); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('日历设置')), body: Center( child: ElevatedButton( // 比如修改日程后手动调用刷新方法即可更新桌面Widget onPressed: refreshDesktopCalendar, child: const Text('同步日历到桌面'), ), ), ); } }
如果需要实现点击Widget上的日期跳转到App对应日程页的交互,直接用home_widget封装的点击跳转接口即可,不需要额外写原生代码。
如果你的日历Widget需要支持滑动、实时动画这类动态效果,位图渲染方案性能不够,再考虑手写MethodChannel嵌入Flutter引擎的方案,普通静态展示+点击交互的日历场景,上面的方案已经足够稳定,线上很多Flutter做的日历Widget都是用这个逻辑实现的。
内容的提问来源于stack exchange,提问作者GamJia
相关产品推荐
相关产品推荐

