Prechádzať zdrojové kódy

优化日程项数量的动态计算

gavin.chen 2 rokov pred
rodič
commit
017fd8612d

+ 36 - 0
lib/calendar_view/month_calendar/month_calendar.dart

@@ -1,5 +1,8 @@
+import 'dart:html';
+
 import 'package:calendar_view/calendar_view/calendar_util.dart';
 import 'package:calendar_view/calendar_view/month_calendar/month_calendar_item.dart';
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 
 class MonthCalendar extends StatefulWidget {
@@ -15,6 +18,8 @@ class _MonthCalendarState extends State<MonthCalendar> {
   int selectedDayIndex = 0; // 当前选择的日期的下标,从0开始,范围是0-34 有时是 0-41
   int maxDaysLength = 35; // 最大的日期数组长度,有时是42
   List<DayStructure> daysList = []; // 当前维护的日期列表
+  int _maxScheduleLines = 3; // 最大的日程行数【需要动态计算】
+  double _viewHeight = 0; // 维护一个视口高度,如果视口高度不变,那么日程的高度不需要计算
 
   @override
   void initState() {
@@ -50,6 +55,20 @@ class _MonthCalendarState extends State<MonthCalendar> {
       DateTime(2022, 12, 31),
     ];
     _setSchedule(mockSchedule);
+
+    /// 监控resize事件,动态计算最大日程行数
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      _handleMaxScheduleLines();
+    });
+
+    /// web端监听resize事件
+    if (kIsWeb) {
+      window.onResize.listen((event) {
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          _handleMaxScheduleLines();
+        });
+      });
+    }
   }
 
   @override
@@ -141,6 +160,7 @@ class _MonthCalendarState extends State<MonthCalendar> {
         child: MonthDayItem(
           dayData: day,
           onSelect: (v) => _handleSelectedDayByIndex(v),
+          maxScheduleLines: _maxScheduleLines,
         ),
       ),
     );
@@ -287,4 +307,20 @@ class _MonthCalendarState extends State<MonthCalendar> {
     _selectFirstDay();
     setState(() {});
   }
+
+  /// 动态计算日历格内的最大日程行数
+  void _handleMaxScheduleLines() {
+    final size = MediaQuery.of(context).size;
+    if (size.height == _viewHeight) return;
+    print('计算最大日程行数');
+    _viewHeight = size.height;
+    final gridRows = (maxDaysLength / 7).floor();
+    final gridHeight = size.height - 100; // 100 是日历头部的高度
+    final gridItemHeight = gridHeight / gridRows;
+    final scheduleAreaHeight = gridItemHeight - 30; // 30 是日期的高度
+    final maxLines = (scheduleAreaHeight / 20).floor();
+    setState(() {
+      _maxScheduleLines = maxLines;
+    });
+  }
 }

+ 11 - 7
lib/calendar_view/month_calendar/month_calendar_item.dart

@@ -6,9 +6,15 @@ import 'package:flutter/services.dart';
 /// 月历的每一格日期
 class MonthDayItem extends StatefulWidget {
   const MonthDayItem(
-      {super.key, required this.dayData, required this.onSelect});
+      {super.key,
+      required this.dayData,
+      required this.onSelect,
+      required this.maxScheduleLines});
   final DayStructure dayData;
   final ValueChanged<int> onSelect;
+  final int maxScheduleLines;
+
+  /// 最大能容纳的日程条数
   @override
   State<MonthDayItem> createState() => _MyWidgetState();
 }
@@ -85,15 +91,12 @@ class _MyWidgetState extends State<MonthDayItem> {
             Container(
               decoration: containerDecoration,
               margin: const EdgeInsets.all(3),
-              height: 25,
-              width: 25,
+              height: 24,
+              width: 24,
               child: Center(
                 child: Text(displayStr, style: dayTextStyle),
               ),
             ),
-            const SizedBox(
-              height: 2,
-            ),
             _buildScheduleContainer()
           ],
         ),
@@ -104,9 +107,10 @@ class _MyWidgetState extends State<MonthDayItem> {
   /// 构建日程容器
   Widget _buildScheduleContainer() {
     return Expanded(
+      // ignore: sized_box_for_whitespace
       child: Container(
         width: double.infinity,
-        child: const ScheduleList(),
+        child: ScheduleList(maxLines: widget.maxScheduleLines),
       ),
     );
   }

+ 67 - 44
lib/calendar_view/month_calendar/schedule_list.dart

@@ -1,10 +1,16 @@
-import 'dart:html';
+import 'dart:math';
+
 import 'package:calendar_view/calendar_view/calendar_util.dart';
 import 'package:flutter/material.dart';
-import 'package:calendar_view/utils/throttle.dart' as utils;
 
 class ScheduleList extends StatefulWidget {
-  const ScheduleList({Key? key}) : super(key: key);
+  const ScheduleList({Key? key, required this.maxLines}) : super(key: key);
+
+  /// 可容纳的最大日程行数
+  final int maxLines;
+
+  /// 每行日程的高度
+  final double itemHeight = 20;
 
   @override
   ScheduleListState createState() => ScheduleListState();
@@ -17,53 +23,35 @@ class ScheduleListState extends State<ScheduleList> {
     ScheduleType(typeName: '学习', isSelected: false, color: Colors.green),
     ScheduleType(typeName: '生活', isSelected: false, color: Colors.orange),
     ScheduleType(typeName: '核酸', isSelected: false, color: Colors.purple),
+    ScheduleType(typeName: '工作', isSelected: true, color: Colors.blue),
+    ScheduleType(typeName: '加班', isSelected: false, color: Colors.red),
+    ScheduleType(typeName: '学习', isSelected: false, color: Colors.green),
+    ScheduleType(typeName: '生活', isSelected: false, color: Colors.orange),
+    ScheduleType(typeName: '核酸', isSelected: false, color: Colors.purple),
   ];
-  static List<ScheduleType> _scheduleTypeList = [];
-
-  /// 容器高度【动态】
-  double conatinerHeight = 0;
-
-  /// 每个item的高度
-  static const double _itemHeight = 20;
+  List<ScheduleType> _scheduleTypeList = [];
 
   /// 容纳的数量
-  int itemCount = 0;
+  int _itemCount = 0;
 
   @override
   void initState() {
     super.initState();
-    _scheduleTypeList = _mockScheduleTypeList;
-    window.onResize.listen(((event) => {
-          utils.throttle(() {
-            _onWindowResize();
-          }, 'onResize_${widget.hashCode}', 500)
-        }));
-    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-      _onWindowResize();
-    });
-  }
 
-  void _onWindowResize() {
-    setState(() {
-      conatinerHeight = context.size!.height;
-      itemCount = _countItemNum();
-    });
-    _scheduleTypeList = _mockScheduleTypeList;
-    // 如果缩减了数量,则将最后一项显示的内容设置为更多
-    if (itemCount < _scheduleTypeList.length) {
-      _scheduleTypeList[itemCount - 1] = ScheduleType(
-          typeName: '还有${_scheduleTypeList.length - itemCount + 1}项...',
-          isSelected: false,
-          color: Colors.grey);
-    }
+    /// 填充假数据
+    final int random = Random().nextInt(10);
+    _scheduleTypeList = _mockScheduleTypeList.sublist(0, random);
+    _itemCount = _scheduleTypeList.length > widget.maxLines
+        ? widget.maxLines
+        : _scheduleTypeList.length;
   }
 
-  /// 计算可容纳的item数量
-  int _countItemNum() {
-    final maxNum = (conatinerHeight / _itemHeight).floor();
-    return maxNum > _scheduleTypeList.length
-        ? _scheduleTypeList.length
-        : maxNum;
+  @override
+  void didUpdateWidget(ScheduleList oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    _itemCount = _scheduleTypeList.length > widget.maxLines
+        ? widget.maxLines
+        : _scheduleTypeList.length;
   }
 
   @override
@@ -75,16 +63,26 @@ class ScheduleListState extends State<ScheduleList> {
 
   Widget _buildScheduleTypeList() {
     return ListView.builder(
-      itemCount: itemCount,
+      addAutomaticKeepAlives: false,
+      addRepaintBoundaries: true,
+      itemExtent: widget.itemHeight,
+      itemCount: _itemCount,
       itemBuilder: (context, index) {
-        return _buildScheduleTypeItem(_scheduleTypeList[index]);
+        return _buildScheduleTypeItem(index);
       },
     );
   }
 
-  Widget _buildScheduleTypeItem(ScheduleType scheduleType) {
+  Widget _buildScheduleTypeItem(int scheduleIndex) {
+    /// TODO: 判断如果构建的是展示的最后一项,但不是列表的最后一项,则需要添加点击事件,并显示“还有${_scheduleTypeList.length - _itemCount + 1}项...”
+    if (scheduleIndex == _itemCount - 1) {
+      if (_itemCount < _scheduleTypeList.length) {
+        return _buildMoreItemButton(_scheduleTypeList.length - _itemCount + 1);
+      }
+    }
+    ScheduleType scheduleType = _scheduleTypeList[scheduleIndex];
     return Container(
-      height: _itemHeight,
+      height: widget.itemHeight,
       padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
       color: Colors.transparent,
       child: Row(
@@ -106,4 +104,29 @@ class ScheduleListState extends State<ScheduleList> {
       ),
     );
   }
+
+  Widget _buildMoreItemButton(int moreNum) {
+    return Container(
+      height: widget.itemHeight,
+      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
+      color: Colors.transparent,
+      child: Row(
+        children: [
+          Container(
+            width: 6,
+            height: 6,
+            decoration: BoxDecoration(
+              color: Colors.transparent,
+              borderRadius: BorderRadius.circular(5),
+            ),
+          ),
+          const SizedBox(width: 10),
+          Text(
+            '还有$moreNum项...',
+            style: const TextStyle(fontSize: 12),
+          ),
+        ],
+      ),
+    );
+  }
 }