Flutter中SingleChildScrollView的initialScrollOffset不生效问题求助
问题原因
ScrollController的initialScrollOffset仅会在控制器首次绑定到可滚动组件时生效,你每次点击按钮触发setState后,虽然会传入新的currentIndex计算得到新的偏移量,但新创建的ScrollController不会触发滚动位置重新初始化:因为_LineView是无状态组件,且没有设置唯一key,Flutter框架会复用之前的SingleChildScrollView对应的元素节点,旧的控制器依然在生效,新控制器的初始偏移量完全不会被应用。- 你把
ScrollController放在无状态组件的build方法中创建属于错误用法,每次组件build都会生成新的控制器实例,会造成不必要的性能消耗,也无法持久控制滚动视图。
修复方案
将_LineView改为有状态组件,在状态类中持有ScrollController实例,监听currentIndex的变化主动调用滚动方法调整偏移量即可,修改后的代码如下:
import 'package:flutter/material.dart'; import 'package:flutter_storage/managers/screen_util.dart'; class DraftPage extends StatefulWidget { DraftPage({Key? key}) : super(key: key); @override _DraftPageState createState() => _DraftPageState(); } class _DraftPageState extends State<DraftPage> { int index = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Test'), ), body: Column( children: [ SizedBox( width: ScreenUtil.screenWidth, height: 30, child: _LineView(currentIndex: index), ), const SizedBox(height: 20), ElevatedButton( child: const Text('scroll'), onPressed: () { setState(() { index++; }); }, ), ], ), ); } } // 改为有状态组件 class _LineView extends StatefulWidget { const _LineView({Key? key, required this.currentIndex}) : super(key: key); final int currentIndex; @override State<_LineView> createState() => _LineViewState(); } class _LineViewState extends State<_LineView> { // 在状态内持有唯一的ScrollController实例 final ScrollController _controller = ScrollController(keepScrollOffset: false); @override void didUpdateWidget(covariant _LineView oldWidget) { super.didUpdateWidget(oldWidget); // currentIndex变化时主动触发滚动 if (widget.currentIndex != oldWidget.currentIndex) { final targetOffset = widget.currentIndex * 20.0; // 避免偏移量超出滚动范围报错 if (targetOffset >= 0 && targetOffset <= _controller.position.maxScrollExtent) { // 无动画直接滚动 _controller.jumpTo(targetOffset); // 需要滚动动画可以替换为下面的代码 // _controller.animateTo(targetOffset, duration: const Duration(milliseconds: 200), curve: Curves.linear); } } } @override void dispose() { // 销毁控制器避免内存泄漏 _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final row = Row( children: [ Container( width: 1000, height: 30, color: Colors.red, child: const Text('666666666666666666666'), ), ], ); return SingleChildScrollView( controller: _controller, scrollDirection: Axis.horizontal, child: row, ); } }
内容的提问来源于stack exchange,提问作者无夜之星辰
相关产品推荐
相关产品推荐

