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

Flutter Web中自定义ScrollController的ListView.builder不响应PageUp/PageDown如何解决

问题原因

这不是Flutter的已知Bug,属于预期行为。
默认未指定自定义ScrollController时,Web/桌面端的ListView会自动绑定Scaffold提供的PrimaryScrollController,该控制器默认关联页面焦点,因此可以正常响应鼠标滚轮、PageUp/PageDown等输入事件。
当你自定义ScrollController后,对应的滚动组件不会被默认标记为当前页面的主滚动组件,也没有自动获取焦点权限,因此键盘事件无法传递到该组件,导致PageUp/PageDown失效。

修复方案

方案1:给滚动组件配置焦点权限(推荐)

只需要给ListView添加焦点配置,让它可以接收键盘事件即可,无需额外处理滚动逻辑,默认的滚动动画、步长都会和原生行为保持一致。
修改后的完整代码如下:

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 const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late ScrollController _controller;
  // 新增FocusNode
  late FocusNode _listFocusNode;

  @override
  void initState() {
    _controller = ScrollController();
    _listFocusNode = FocusNode();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    _listFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: ListView.builder(
              itemCount: 500,
              controller: _controller,
              // 新增焦点配置
              focusNode: _listFocusNode,
              autofocus: true,
              itemBuilder: (BuildContext context, int i) => Text('Item $i'))),
    );
  }
}

如果页面存在多个可聚焦组件,你可以在需要列表响应键盘事件时,手动调用_listFocusNode.requestFocus()将焦点切换到列表。

方案2:手动监听键盘事件自定义滚动逻辑

如果你需要自定义PageUp/PageDown的滚动步长、动画等效果,可以手动监听键盘事件控制滚动:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late ScrollController _controller;

  @override
  void initState() {
    _controller = ScrollController();
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        // 用KeyboardListener包裹ListView
        child: KeyboardListener(
          focusNode: FocusNode(),
          autofocus: true,
          onKeyEvent: (event) {
            // 每次滚动的步长,这里取当前视口高度,和默认PageUp/PageDown行为一致
            final pageHeight = MediaQuery.of(context).size.height;
            const scrollDuration = Duration(milliseconds: 200);
            if (event.logicalKey == LogicalKeyboardKey.pageDown) {
              _controller.animateTo(
                _controller.offset + pageHeight,
                duration: scrollDuration,
                curve: Curves.easeInOut,
              );
              return KeyEventResult.handled;
            } else if (event.logicalKey == LogicalKeyboardKey.pageUp) {
              _controller.animateTo(
                _controller.offset - pageHeight,
                duration: scrollDuration,
                curve: Curves.easeInOut,
              );
              return KeyEventResult.handled;
            }
            return KeyEventResult.ignored;
          },
          child: ListView.builder(
            itemCount: 500,
            controller: _controller,
            itemBuilder: (BuildContext context, int i) => Text('Item $i'),
          ),
        ),
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 09:45:07