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

Flutter带月份导航的PageViewBuilder逻辑问题排查与代码修复

CrewHours页面月份导航逻辑修复

问题排查

  1. 后退按钮失效原因:原代码后退判断条件newPageIndex < 12完全错误,PageView索引从0开始,正确限制应为newPageIndex >= 0,否则无法跳转到更早月份对应的索引页面。
  2. 前进按钮不符合需求:原代码允许跳转到全年12月,但需求限制最多往后3个月,需结合当前实际月份做判断。
  3. 初始索引逻辑混乱:原_currentPageIndex = 1导致初始页面不是当前月份,需修正为对应当前月份的索引。
  4. 页面数量不符合补充需求:原固定12个页面,需改为动态计算:展示当年已过的所有月份+下一个月。

修复后的完整代码

import 'package:bha_roster/presentation/my_colors.dart';
import 'package:bha_roster/utils/config.dart';
import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';

class CrewHours extends StatefulWidget {
  const CrewHours({Key? key}) : super(key: key);
  @override
  _CrewHoursState createState() => _CrewHoursState();
}

class _CrewHoursState extends State<CrewHours> with SingleTickerProviderStateMixin {
  late TabController _tabController;
  late PageController _pageController;
  int _currentPageIndex = 0;
  final DateTime _now = DateTime.now();

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    // 初始索引对应当前月份(比如8月对应索引7,0=1月)
    _currentPageIndex = _now.month - 1;
    _pageController = PageController(initialPage: _currentPageIndex);
  }

  @override
  void dispose() {
    _tabController.dispose();
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 计算可展示的页面数量:已过月份+下一个月(比如当前8月,展示1-9月,共9个)
    final int totalPages = _now.month + 1;

    return Scaffold(
      body: Column(
        children: [
          TabBar(
            physics: const NeverScrollableScrollPhysics(),
            controller: _tabController,
            indicator: const BoxDecoration(
              borderRadius: BorderRadius.only(
                topLeft: Radius.circular(10),
                topRight: Radius.circular(10),
              ),
              color: MyColors.primarySwatch,
            ),
            labelColor: Colors.white,
            indicatorColor: const Color.fromARGB(255, 102, 249, 4),
            indicatorSize: TabBarIndicatorSize.tab,
            unselectedLabelColor: Colors.black,
            tabs: const [
              Tab(text: 'Captain'),
              Tab(text: 'First Officer'),
              Tab(text: 'Cabin Crew'),
            ],
          ),
          Expanded(
            child: PageView.builder(
              physics: const NeverScrollableScrollPhysics(),
              controller: _pageController,
              onPageChanged: (index) {
                setState(() {
                  _currentPageIndex = index;
                });
              },
              itemBuilder: (context, index) {
                // index直接对应月份:index=0→1月,index=11→12月
                final month = index + 1;
                final year = _now.year;
                final monthName = getMonthName(month);
                return Scaffold(
                  appBar: AppBar(
                    title: Text('$monthName $year'),
                  ),
                  body: Column(
                    children: [
                      Expanded(
                        child: Center(child: Text('$monthName $year')),
                      ),
                    ],
                  ),
                  bottomNavigationBar: BottomAppBar(
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        IconButton(
                          icon: const Icon(Icons.arrow_back_ios),
                          onPressed: () {
                            final newPageIndex = _currentPageIndex - 1;
                            // 后退允许到索引0(对应1月)
                            if (newPageIndex >= 0) {
                              _pageController.animateToPage(
                                newPageIndex,
                                duration: const Duration(milliseconds: 500),
                                curve: Curves.easeInOut,
                              );
                            }
                          },
                        ),
                        Text('${getMonthName(_currentPageIndex + 1)} ${_now.year}'),
                        IconButton(
                          icon: const Icon(Icons.arrow_forward_ios),
                          onPressed: () {
                            final newPageIndex = _currentPageIndex + 1;
                            // 前进限制:最多到当前月份+3(比如当前8月,最多到11月,对应索引10)
                            final maxAllowedMonth = _now.month + 3;
                            final maxAllowedIndex = maxAllowedMonth - 1;
                            // 同时不能超过可展示的页面总数(已过月份+下一个月)
                            if (newPageIndex <= maxAllowedIndex && newPageIndex < totalPages) {
                              _pageController.animateToPage(
                                newPageIndex,
                                duration: const Duration(milliseconds: 500),
                                curve: Curves.easeInOut,
                              );
                            }
                          },
                        ),
                      ],
                    ),
                  ),
                );
              },
              itemCount: totalPages,
            ),
          ),
        ],
      ),
    );
  }

  String getMonthName(int month) {
    switch (month) {
      case 1:
        return 'January';
      case 2:
        return 'February';
      case 3:
        return 'March';
      case 4:
        return 'April';
      case 5:
        return 'May';
      case 6:
        return 'June';
      case 7:
        return 'July';
      case 8:
        return 'August';
      case 9:
        return 'September';
      case 10:
        return 'October';
      case 11:
        return 'November';
      case 12:
        return 'December';
      default:
        return '';
    }
  }
}

关键修改说明

  • 索引与月份对应关系修正:将index直接对应月份(index=0→1月,index=7→8月),避免原代码中混乱的月份计算逻辑。
  • 后退按钮逻辑修复:判断条件改为newPageIndex >=0,允许回到当年1月。
  • 前进按钮限制:新增maxAllowedMonth限制最多往后3个月,同时结合totalPages确保不超出补充需求的展示范围。
  • 动态页面数量:totalPages = _now.month +1,实现展示已过所有月份+下一个月的需求。
  • 初始索引修正:_currentPageIndex = _now.month -1,确保打开页面默认显示当前月份。

内容的提问来源于stack exchange,提问作者Pannam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 06:35:13