Flutter:点击Done按钮隐藏键盘后,让SingleChildScrollView自动滚回初始偏移
问题:点击Done按钮后让SingleChildScrollView滚动回初始位置
我在SingleChildScrollView内放置了一个包含两个TextField的堆叠Card,需求是在两个TextField填写完成并点击Done按钮后,让SingleChildScrollView立刻滚动回initialScrollOffset。目前的实现未达到预期效果——只有手动向下滚动Card时,autoBackToPosition函数才会触发。

当前代码:
class Takok extends StatefulWidget { const Takok({super.key}); @override State<Takok> createState() => _TakokState(); } class _TakokState extends State<Takok> with TickerProviderStateMixin { TextEditingController user = TextEditingController(); TextEditingController pass = TextEditingController(); ScrollController _scrollController = ScrollController(); void autoBackToPosition() { if (_scrollController.offset > 100) { _scrollController.animateTo(_scrollController.initialScrollOffset, duration: const Duration(milliseconds: 500), curve: Curves.decelerate); } } @override void initState() { _scrollController.addListener(autoBackToPosition); super.initState(); } @override void dispose() { user.dispose(); pass.dispose(); _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Stack( children: [ Positioned.fill( child: Container( color: Colors.amber, )), Align( alignment: Alignment.bottomCenter, child: SingleChildScrollView( controller: _scrollController, physics: const BouncingScrollPhysics(), child: Container( margin: EdgeInsets.only( top: MediaQuery.of(context).size.height * .32), height: MediaQuery.of(context).size.height, child: Card( elevation: 6, margin: const EdgeInsets.symmetric(horizontal: 20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24)), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 6), child: Column( children: [ SizedBox( height: 50, ), TextField( textInputAction: TextInputAction.next, ), SizedBox( height: 20, ), TextField(), SizedBox( height: 30, ), Spacer() ], ), ), ), ), ), ) ], )), ); } }
问题原因
你把回滚逻辑绑定在了ScrollController的listener上,只有发生滚动行为时才会触发这个函数,但点击Done按钮并不会触发滚动事件,所以回滚逻辑不会自动执行。
修复方案
- 给第二个TextField设置
textInputAction: TextInputAction.done,让键盘显示Done按钮; - 添加
onSubmitted回调,在用户点击Done时主动调用回滚函数; - 移除ScrollController的listener,避免不必要的触发。
修改后的完整代码:
class Takok extends StatefulWidget { const Takok({super.key}); @override State<Takok> createState() => _TakokState(); } class _TakokState extends State<Takok> with TickerProviderStateMixin { TextEditingController user = TextEditingController(); TextEditingController pass = TextEditingController(); ScrollController _scrollController = ScrollController(); void autoBackToPosition() { if (_scrollController.offset > 100) { _scrollController.animateTo( _scrollController.initialScrollOffset, duration: const Duration(milliseconds: 500), curve: Curves.decelerate, ); // 可选:收起键盘 FocusScope.of(context).unfocus(); } } @override void initState() { // 移除滚动监听,改为在Done点击时触发 super.initState(); } @override void dispose() { user.dispose(); pass.dispose(); _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Stack( children: [ Positioned.fill(child: Container(color: Colors.amber)), Align( alignment: Alignment.bottomCenter, child: SingleChildScrollView( controller: _scrollController, physics: const BouncingScrollPhysics(), child: Container( margin: EdgeInsets.only( top: MediaQuery.of(context).size.height * .32, ), height: MediaQuery.of(context).size.height, child: Card( elevation: 6, margin: const EdgeInsets.symmetric(horizontal: 20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 6, ), child: Column( children: [ const SizedBox(height: 50), TextField( textInputAction: TextInputAction.next, controller: user, // 绑定控制器 ), const SizedBox(height: 20), TextField( textInputAction: TextInputAction.done, // 设置为Done按钮 controller: pass, // 绑定控制器 onSubmitted: (value) { // 点击Done时触发回滚 autoBackToPosition(); }, ), const SizedBox(height: 30), const Spacer() ], ), ), ), ), ), ) ], ), ), ); } }
关键修改点
- 第二个TextField添加
textInputAction: TextInputAction.done,让键盘显示Done按钮; - 添加
onSubmitted回调,在用户点击Done时直接调用autoBackToPosition; - 移除
initState中的滚动监听,避免滚动时误触发回滚; - 可选:在回滚函数中添加
FocusScope.of(context).unfocus(),点击Done后自动收起键盘,体验更流畅。
内容的提问来源于stack exchange,提问作者pras
相关产品推荐
相关产品推荐

