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

Flutter中同步ListWheelScrollView:FixedExtentScrollPhysics适配难题

解决ListWheelScrollView双向同步滚动(兼容FixedExtentScrollPhysics)

针对两个ListWheelScrollView双向滚动卡顿、linked_scroll_controller不兼容FixedExtentScrollPhysics的问题,直接自己实现同步逻辑即可解决,无需依赖第三方包。

核心解决思路

  1. 给两个列表分别配置FixedExtentScrollController,独立控制各自的滚动
  2. 添加一个布尔标记位,防止同步时触发循环回调(比如A同步B时,B的滚动回调不会反过来再同步A)
  3. 利用列表的选中项变化回调(或控制器滚动监听),直接调用jumpToItem同步位置——这个方法比animateToItem更贴合ListWheelScrollView的对齐特性,不会产生动画延迟导致的卡顿

完整代码实现

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '双向同步列表',
      theme: ThemeData(primarySwatch: Colors.blue),
      debugShowCheckedModeBanner: false,
      home: const SyncListWheelPage(),
    );
  }
}

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

class _SyncListWheelPageState extends State<SyncListWheelPage> {
  final _greenController = FixedExtentScrollController();
  final _redController = FixedExtentScrollController();
  bool _isSyncing = false;

  @override
  void dispose() {
    _greenController.dispose();
    _redController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("双向同步列表"),
        backgroundColor: Colors.green,
      ),
      body: Row(
        children: [
          SizedBox(
            height: 600,
            width: 300,
            child: ListWheelScrollView(
              itemExtent: 100,
              physics: const FixedExtentScrollPhysics(),
              controller: _greenController,
              onSelectedItemChanged: (index) {
                if (_isSyncing) return;
                _isSyncing = true;
                _redController.jumpToItem(index);
                _isSyncing = false;
              },
              children: [
                for (int i = 0; i < 5; i++)
                  Container(
                    color: Colors.green,
                    height: 50,
                    width: 50,
                  )
              ],
            ),
          ),
          SizedBox(
            height: 600,
            width: 300,
            child: ListWheelScrollView(
              itemExtent: 100,
              physics: const FixedExtentScrollPhysics(),
              controller: _redController,
              onSelectedItemChanged: (index) {
                if (_isSyncing) return;
                _isSyncing = true;
                _greenController.jumpToItem(index);
                _isSyncing = false;
              },
              children: [
                for (int i = 0; i < 5; i++)
                  Container(
                    color: Colors.red,
                    height: 50,
                    width: 50,
                  )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

关键细节说明

  • 用onSelectedItemChanged替代滚动监听:这个回调是ListWheelScrollView专门针对选中项变化设计的,比监听控制器滚动更精准,避免不必要的同步触发
  • _isSyncing标记位:彻底解决双向同步时的循环回调问题,确保只有主动操作的列表才会触发同步
  • jumpToItem方法:直接让目标列表跳转到对应项,完全贴合FixedExtentScrollPhysics的对齐逻辑,滚动过程无卡顿延迟

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:25:26