Flutter实现每日8小时使用后禁用CupertinoButton的问题
需求是让CupertinoButton在当日累计使用满8小时后自动禁用,8小时内可无限制点击。你之前尝试用秒数范围判断的方式没生效,问题出在两个地方:一是逻辑不对(你要的是累计使用时长,不是当前秒数区间),二是这种写法只会在Widget首次构建时计算一次,不会随时间或使用情况自动更新状态。
下面是可行的解决方案:
核心思路
- 用持久化存储记录每日累计使用时长,确保App重启后数据不丢失
- 维护按钮的可用状态,实时判断是否达到8小时上限
- 点击按钮时更新累计时长,并动态同步状态
具体实现步骤
1. 先添加依赖(如果没装的话)
在pubspec.yaml里加入用于本地存储的依赖:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2
2. 完整代码示例
import 'package:flutter/cupertino.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:ionicons/ionicons.dart'; // 假设这是你的页面组件 class UsageLimitedPage extends StatefulWidget { const UsageLimitedPage({super.key}); @override State<UsageLimitedPage> createState() => _UsageLimitedPageState(); } class _UsageLimitedPageState extends State<UsageLimitedPage> { int _totalUsageSeconds = 0; // 当日累计使用时长(秒) String _currentDate = ''; // 记录当前日期,区分不同天数 bool _isButtonEnabled = true; // 按钮是否可用 final int _usagePerClick = 60; // 每次点击的使用时长(这里假设1分钟,可根据实际调整) @override void initState() { super.initState(); _loadSavedUsageData(); // 每分钟检查一次状态,确保时间到了自动禁用按钮 Future.doWhile(() async { await Future.delayed(const Duration(minutes: 1)); _checkButtonStatus(); return true; }); } // 加载本地存储的当日使用数据 Future<void> _loadSavedUsageData() async { final prefs = await SharedPreferences.getInstance(); final today = DateTime.now().toString().split(' ')[0]; // 获取当日日期字符串,比如"2024-05-20" _currentDate = today; _totalUsageSeconds = prefs.getInt('daily_usage_$today') ?? 0; _checkButtonStatus(); setState(() {}); } // 判断按钮是否应该禁用 void _checkButtonStatus() { const int maxDailyUsage = 8 * 60 * 60; // 8小时换算成秒 setState(() { _isButtonEnabled = _totalUsageSeconds < maxDailyUsage; }); } // 处理按钮点击逻辑 Future<void> _onMenuButtonPressed() async { if (!_isButtonEnabled) return; // 更新累计使用时长 setState(() { _totalUsageSeconds += _usagePerClick; }); // 保存到本地存储 final prefs = await SharedPreferences.getInstance(); await prefs.setInt('daily_usage_$_currentDate', _totalUsageSeconds); // 执行你原本的按钮逻辑,比如打开菜单等 // 替换成你自己的业务代码 // ... } @override Widget build(BuildContext context) { return CupertinoPageScaffold( child: SafeArea( child: Column( children: [ Align( alignment: Alignment.centerLeft, child: CupertinoButton( onPressed: _isButtonEnabled ? _onMenuButtonPressed : null, minSize: 0, padding: const EdgeInsets.all(8), child: Icon( Ionicons.menu, // 禁用时图标变灰,提升用户感知 color: _isButtonEnabled ? const ColorPalette.neutral50 : CupertinoColors.inactiveGray, ), ), ), ], ), ), ); } }
关键细节说明
- 持久化存储:按日期存储每日数据,避免跨天累计,确保每天0点后按钮自动恢复可用
- 状态更新:通过
setState实时刷新按钮状态,定时检查确保时间到了自动禁用 - 用户体验:禁用时图标变灰,让用户直观知道按钮不可用
- 灵活调整:
_usagePerClick可以根据实际场景修改,比如如果是记录每次使用的实际时长,可以在点击后计算真实使用时间再累加
内容的提问来源于stack exchange,提问作者Tommz
相关产品推荐
相关产品推荐

