Flutter Quill编辑器无法随用户输入自动滚动问题求助
解决flutter_quill嵌套SliverFillRemaining时输入不自动滚动的问题
问题根源
- 每次调用
buildQuillEditorWidget都会重新创建QuillController和ScrollController,导致状态丢失,无法持续跟踪光标位置。 - 编辑器设置了
NeverScrollableScrollPhysics(),且SliverFillRemaining的hasScrollBody: false,使得编辑器自身无法滚动,同时没有将光标位置变化同步到父级CustomScrollView的滚动控制器。
解决方案
- 将
QuillController和父级CustomScrollView的ScrollController提升到页面State中,避免每次重建丢失状态。 - 监听
QuillController的选区变化,当光标位置更新时,计算对应的滚动偏移量,让父级滚动控制器自动滚动到光标可视位置。 - 调整
SliverFillRemaining的配置,确保滚动上下文正确传递。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart' as quill; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: ""), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late final quill.QuillController _bodyController; late final ScrollController _scrollController; @override void initState() { super.initState(); _bodyController = quill.QuillController.basic(); _scrollController = ScrollController(); // 监听光标选区变化,自动滚动到光标位置 _bodyController.addListener(_handleSelectionChange); } @override void dispose() { _bodyController.dispose(); _scrollController.dispose(); super.dispose(); } void _handleSelectionChange() { final selection = _bodyController.selection; if (selection.isValid && selection.isCollapsed) { // 获取光标所在位置的RenderObject final editorContext = _bodyController.editorKey.currentContext; if (editorContext != null) { final renderBox = editorContext.findRenderObject() as RenderBox; final localOffset = _bodyController.getOffsetForCaret(selection.base); // 让父级滚动控制器确保光标位置可视 _scrollController.position.ensureVisible( renderBox, alignment: 0.3, duration: const Duration(milliseconds: 200), ); } } } @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( controller: _scrollController, slivers: [ SliverFillRemaining( hasScrollBody: true, // 改为true,允许子组件参与滚动上下文 child: Padding( padding: const EdgeInsets.all(8.0), child: Container( color: Colors.purple, child: quill.QuillEditor.basic( controller: _bodyController, configurations: const quill.QuillEditorConfigurations( placeholder: "Body", // 可选:保留NeverScrollableScrollPhysics完全依赖父滚动,或移除让编辑器自身滚动 // scrollPhysics: NeverScrollableScrollPhysics(), ), ), ), ), ), ], ), ); } }
关键调整说明
- 将控制器移到State的
initState中初始化,确保状态持久化,避免每次build重建丢失数据。 - 添加
_handleSelectionChange监听方法,当光标位置变化时,通过父级ScrollController的ensureVisible方法自动滚动到光标可视区域。 - 将
SliverFillRemaining的hasScrollBody设为true,确保滚动上下文能正确传递给子组件。 - 可根据需求选择是否保留编辑器的
NeverScrollableScrollPhysics:保留则完全依赖父级滚动,移除则编辑器自身可处理局部滚动。
内容的提问来源于stack exchange,提问作者Akshay
相关产品推荐
相关产品推荐

