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

Flutter中ListWheelScrollView横竖屏切换后位置异常问题

解决ListWheelScrollView返回后页码偏移问题

问题根源

  1. 横竖屏切换触发LayoutBuilder重新计算约束,ListWheelScrollView的itemExtent依赖屏幕宽度,切换后尺寸变化导致滚动位置错乱
  2. RotatedBox的旋转改变了布局坐标系,与ListWheelScrollView的滚动逻辑产生冲突
  3. 原代码使用无状态组件,无法持久化滚动位置,页面返回重建后丢失之前的选中状态

修复方案

将组件改为有状态组件,通过ScrollController控制滚动位置,持久化当前选中索引,返回竖屏后手动恢复滚动位置:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main(List<String> args) {
  runApp(const _Test());
}

class _Test extends StatefulWidget {
  const _Test({super.key});

  @override
  State<_Test> createState() => _TestState();
}

class _TestState extends State<_Test> {
  final ScrollController _scrollController = ScrollController();
  int _currentIndex = 0;

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(),
        body: LayoutBuilder(
          builder: (context, constraints) {
            final itemExtent = constraints.maxWidth;
            return RotatedBox(
              quarterTurns: -1,
              child: ListWheelScrollView.useDelegate(
                controller: _scrollController,
                itemExtent: itemExtent,
                physics: const PageScrollPhysics(),
                perspective: 0.002,
                onSelectedItemChanged: (index) {
                  setState(() {
                    _currentIndex = index % 8; // 适配循环代理的循环特性
                  });
                },
                childDelegate: ListWheelChildLoopingListDelegate(
                  children: List.generate(8, (index) {
                    return RotatedBox(
                      quarterTurns: 1,
                      child: GestureDetector(
                        child: Container(
                          alignment: Alignment.center,
                          color: Colors.primaries[index].shade200,
                          child: Text('<- Push $index ->'),
                        ),
                        onTap: () async {
                          await SystemChrome.setPreferredOrientations([
                            DeviceOrientation.landscapeLeft,
                            DeviceOrientation.landscapeRight,
                          ]);
                          await Navigator.push(context, MaterialPageRoute(builder: (context) {
                            return Scaffold(
                              appBar: AppBar(),
                              body: Center(
                                child: FilledButton(
                                  child: Text('Pop $_currentIndex'),
                                  onPressed: () => Navigator.pop(context),
                                ),
                              ),
                            );
                          }));
                          await SystemChrome.setPreferredOrientations([
                            DeviceOrientation.portraitUp,
                            DeviceOrientation.portraitDown,
                          ]);
                          // 等待布局完成后恢复滚动位置,避免尺寸未稳定导致偏差
                          WidgetsBinding.instance.addPostFrameCallback((_) {
                            _scrollController.animateTo(
                              _currentIndex * itemExtent,
                              duration: const Duration(milliseconds: 100),
                              curve: Curves.easeInOut,
                            );
                          });
                        },
                      ),
                    );
                  }),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

关键修复点

  • 用StatefulWidget持久化_currentIndex和ScrollController,保存当前选中的页码
  • 通过onSelectedItemChanged监听滚动变化,实时更新当前索引(适配循环代理做取模处理)
  • 返回竖屏后,通过addPostFrameCallback等待布局完成,再调用animateTo恢复到之前的索引位置
  • 确保itemExtent在布局重建时正确获取当前屏幕宽度,避免尺寸不匹配导致的滚动偏差

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:05:05