week_page.dart 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import 'package:flutter/material.dart';
  2. import 'package:shared/utils/log_utils.dart';
  3. import 'calendar_utils.dart' show get2Weekdays, addDay, subtractDay, firstDayOfWeek;
  4. import 'day_table_view.dart';
  5. enum PageState {
  6. previous,
  7. current,
  8. next,
  9. }
  10. /// 一周的Days的PageView页面
  11. class WeekPage extends StatefulWidget {
  12. const WeekPage({
  13. super.key,
  14. required this.selectedDate,
  15. required this.now,
  16. required this.isAutoSelect,
  17. this.onChangedSelectedDate,
  18. this.onChangedPage,
  19. });
  20. final DateTime now;
  21. final DateTime selectedDate;
  22. final bool isAutoSelect;
  23. final Function(DateTime)? onChangedSelectedDate; //选择日期变化的监听
  24. final Function(DateTime date, PageState state)? onChangedPage; //切换日期Page的监听
  25. final double height = 40 + 40 + 10;
  26. @override
  27. State<StatefulWidget> createState() => _WeekPageState();
  28. }
  29. class _WeekPageState extends State<WeekPage> {
  30. double get height => widget.height;
  31. final int initialPage = 999;
  32. List<int> pageCounts = [0, 1, 2];
  33. int currentPage = 1;
  34. late DateTime _currentPageDate;
  35. late DateTime _slectedDate;
  36. DateTime get now => widget.now;
  37. DateTime get selectedDate => widget.selectedDate;
  38. late PageController _pageController;
  39. @override
  40. void initState() {
  41. super.initState();
  42. _currentPageDate = selectedDate;
  43. _slectedDate = selectedDate;
  44. _pageController = PageController(initialPage: initialPage);
  45. }
  46. @override
  47. void didUpdateWidget(covariant WeekPage oldWidget) {
  48. super.didUpdateWidget(oldWidget);
  49. if (widget.selectedDate != oldWidget.selectedDate) {
  50. setState(() {
  51. _currentPageDate = widget.selectedDate;
  52. _slectedDate = widget.selectedDate;
  53. });
  54. // 计算要滚动到的页面索引
  55. int targetPageIndex = _calculateTargetPageIndex(widget.selectedDate);
  56. // 使用 WidgetsBinding 以确保在构建完成后再跳转页面
  57. WidgetsBinding.instance.addPostFrameCallback((_) {
  58. // 检查目标页面索引是否在有效范围内
  59. Log.d("targetPageIndex:$targetPageIndex pageCounts.length:${pageCounts.length}");
  60. if (targetPageIndex >= 0 && targetPageIndex < pageCounts.length) {
  61. _pageController.jumpToPage(targetPageIndex);
  62. } else {
  63. //超过了索引就刷新数据源?
  64. Log.d("超过了索引就刷新数据源");
  65. }
  66. });
  67. }
  68. }
  69. // 计算要滚动到的页面索引
  70. int _calculateTargetPageIndex(DateTime date) {
  71. // 获取当前周的第一天
  72. DateTime currentFirstDayOfWeek = firstDayOfWeek(now);
  73. // 获取选中日期的周的第一天
  74. DateTime targetFirstDayOfWeek = firstDayOfWeek(date);
  75. // 计算当前日期与目标日期之间的天数差
  76. int differenceInDays = targetFirstDayOfWeek.difference(currentFirstDayOfWeek).inDays + 1;
  77. // 计算目标页面索引
  78. // 每页14天
  79. int targetPageIndex = (differenceInDays / 14).floor(); // 用floor确保向下取整
  80. // 确保目标索引在有效范围内
  81. // targetPageIndex = (targetPageIndex + pageCounts.length) % pageCounts.length;
  82. Log.d("differenceInDays:$differenceInDays targetPageIndex:$targetPageIndex");
  83. return targetPageIndex;
  84. }
  85. @override
  86. Widget build(BuildContext context) {
  87. return Flexible(
  88. child: AnimatedSize(
  89. duration: const Duration(milliseconds: 250),
  90. curve: Curves.easeInOut,
  91. alignment: Alignment.topCenter,
  92. child: SizedBox(
  93. height: height,
  94. child: pageViewBuilder(),
  95. ),
  96. ),
  97. );
  98. }
  99. //PageView的方式展示不同的星期,每周每一个Page
  100. Widget pageViewBuilder() {
  101. return PageView.builder(
  102. itemBuilder: (context, index) {
  103. final idx = _getIndex(index);
  104. return dayTable(idx);
  105. },
  106. onPageChanged: onPageChanged,
  107. controller: _pageController,
  108. );
  109. }
  110. //两周的数据
  111. Widget dayTable(int index) {
  112. int at = pageCounts[index] - 1;
  113. final weekdays = get2Weekdays(now, at);
  114. return DayTableView(
  115. weekdays: weekdays,
  116. onSelect: (date) {
  117. setState(() {
  118. _slectedDate = date;
  119. });
  120. //主动点击之后回调
  121. widget.onChangedSelectedDate?.call(date);
  122. },
  123. selectedDate: _slectedDate,
  124. currentDate: now,
  125. );
  126. }
  127. //是否需要切换页面的时候自动选中
  128. void changeSelectedDate(int value) {
  129. if (_pageState(value) == PageState.next) {
  130. if (widget.isAutoSelect) {
  131. _slectedDate = addDay(selectedDate, 14);
  132. widget.onChangedSelectedDate?.call(_slectedDate);
  133. }
  134. } else {
  135. if (widget.isAutoSelect) {
  136. _slectedDate = subtractDay(selectedDate, 14);
  137. widget.onChangedSelectedDate?.call(_slectedDate);
  138. }
  139. }
  140. }
  141. //当切换页面的时候更新当前页面数据,返回当前页面第一条数据的日期
  142. void updateCurrentPageDate(int value) {
  143. final first = firstDayOfWeek(_currentPageDate);
  144. if (_pageState(value) == PageState.next) {
  145. _currentPageDate = addDay(first, 14);
  146. widget.onChangedPage?.call(_currentPageDate, PageState.next);
  147. } else {
  148. _currentPageDate = subtractDay(first, 14);
  149. widget.onChangedPage?.call(_currentPageDate, PageState.previous);
  150. }
  151. }
  152. void onPageChanged(int value) {
  153. changeSelectedDate(value);
  154. updateCurrentPageDate(value);
  155. int currentIndex = _getIndex(value);
  156. int leftIndex = (currentIndex - 1 < 0) ? pageCounts.length - 1 : currentIndex - 1;
  157. int rightIndex = (currentIndex + 1 > pageCounts.length - 1) ? 0 : currentIndex + 1;
  158. pageCounts[leftIndex] = pageCounts[currentIndex] - 1;
  159. pageCounts[rightIndex] = pageCounts[currentIndex] + 1;
  160. currentPage = pageCounts[currentIndex];
  161. }
  162. int _getIndex(int idx) {
  163. return (idx + 1) % pageCounts.length;
  164. }
  165. PageState _pageState(int idx) {
  166. final prePage = currentPage;
  167. final current = pageCounts[_getIndex(idx)];
  168. return (prePage < current) ? PageState.next : PageState.previous;
  169. }
  170. }