Flutter中OutlinedButton偶发StackOverflowError问题求助
错误日志
======== 由widgets库捕获的异常 ======================================================= 构建OutlinedButton(style: ButtonStyle#dc6a2(foregroundColor: _OutlinedButtonDefaultColor#e3bc0, overlayColor: _OutlinedButtonDefaultOverlay#5f70a, side: MaterialStatePropertyAll(BorderSide(width: 0.0, style: none))), dependencies: [MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#28c3a]], state: _ButtonStyleState#ac5c5)时抛出以下StackOverflowError: Stack Overflow 相关错误触发组件: OutlinedButton OutlinedButton:file:///Users/mac/Documents/flutter_projects/zense_timer_project/zense_timer/lib/pages/home_page/banner_settings/custom_home_button.dart:35:20 异常抛出时的调用栈: #0 _LerpProperties.resolve (package:flutter/src/material/material_state.dart:693:3) #1 _LerpProperties.resolve (package:flutter/src/material/material_state.dart:695:29) #2 _LerpProperties.resolve (package:flutter/src/material/material_state.dart:695:29) ...(中间重复栈帧省略) #4232 RenderStack._computeSize (package:flutter/src/rendering/stack.dart:580:43) #4233 RenderStack.performLayout (package:flutter/src/rendering/stack.dart:607:12) #4234 RenderObject.layout (package:flutter/src/rendering/object.dart:2395:7) ...(后续布局栈帧省略) ====================================================================================================
注意:目前仅在iPhone模拟器上触发该错误,Android模拟器未出现此问题。
相关代码
自定义按钮所在的Row容器代码
return Align( alignment: Alignment.bottomCenter, child: SizedBox( height: kToolbarHeight * 1.25, width: size.width, child: appState.sessionState == SessionState.notStarted ? IgnorePointer( ignoring: appState.sessionState != SessionState.notStarted, child: Container( decoration: BoxDecoration( color: backgroundColor, borderRadius: const BorderRadius.only( topLeft: Radius.circular(kBorderRadiusBig), topRight: Radius.circular(kBorderRadiusBig), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ CustomHomeButton( title: bellTitle, iconData: !audioState.bellOnStart && audioState.bellSound.name == kNone && audioState.bellOnEndSound.name == kNone ? FontAwesomeIcons.bellSlash : FontAwesomeIcons.bell, onPressed: () { /// 回调代码... }, ), CustomHomeButton( title: audioState.ambience.toText(), iconData: audioState.ambience.toIcon(), onPressed: () async { /// 回调代码... }, ), CustomHomeButton( title: appState.selectedPreset == "" ? kPresets : appState.selectedPreset, iconData: Icons.tune_outlined, onPressed: () { /// 回调代码... }), //// 其他按钮...
自定义按钮组件代码
import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:zense_timer/configs/constants.dart'; import 'package:zense_timer/state/app_state.dart'; class CustomHomeButton extends StatelessWidget { const CustomHomeButton({ super.key, required this.iconData, required this.onPressed, this.title, }); final String? title; final IconData iconData; final VoidCallback onPressed; @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return SizedBox( width: size.width / 4, height: size.height * 0.8, // 存在布局约束问题 child: OutlinedButton( style: OutlinedButton.styleFrom( side: BorderSide.none, // 可能触发样式插值递归 ), onPressed: onPressed, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( padding: EdgeInsets.symmetric(vertical: size.height * 0.003), child: Center(child: Icon(iconData)), ), SizedBox( width: size.width / 4, height: size.height * 0.018, child: title != null ? Text( title!, textAlign: TextAlign.center, style: Theme.of(context) .textTheme .labelSmall! .copyWith( color: Theme.of(context).colorScheme.onBackground, fontSize: 8,), maxLines: 1, overflow: TextOverflow.ellipsis, ) : null, ), ], ), ), ); } }
解决方案
问题根源
- 布局约束冲突:CustomHomeButton内部的SizedBox设置了
height: size.height * 0.8,但父容器高度仅为kToolbarHeight * 1.25(约70),远小于按钮设置的高度,导致iOS布局系统计算约束时触发无限递归。 - 样式插值递归:
BorderSide.none与OutlinedButton默认样式的插值逻辑冲突,_LerpProperties.resolve方法递归解析样式时出现无限调用。
修复步骤
- 修正按钮高度约束:将CustomHomeButton中的SizedBox高度改为
double.infinity,让按钮自动填充父容器高度,避免约束冲突:SizedBox( width: size.width / 4, height: double.infinity, // 替换原有的size.height * 0.8 child: OutlinedButton( // ...其他代码 ), ) - 调整边框样式设置:不要使用
BorderSide.none,改用BorderSide(width: 0),或者直接替换为TextButton(无需边框时更贴合需求):// 方案1:修改side参数 style: OutlinedButton.styleFrom( side: const MaterialStatePropertyAll(BorderSide(width: 0)), ), // 方案2:替换为TextButton child: TextButton( style: TextButton.styleFrom(padding: EdgeInsets.zero), onPressed: onPressed, child: Column(/* ...原有子组件 */), ) - 清理冗余布局:外层已判断
appState.sessionState == SessionState.notStarted,可以简化IgnorePointer的条件:IgnorePointer( ignoring: appState.sessionState != SessionState.notStarted, child: Container(/* ... */), )
内容的提问来源于stack exchange,提问作者Kdon
相关产品推荐
相关产品推荐

