在PageView中使用Google Maps遇超大文本错误,求解决
Flutter PageView 嵌入 Google Maps 超大文本错误修复方案
问题场景
在Flutter项目中,将Google Maps组件放入PageView后出现超大文本显示异常,错误截图如下:
相关代码
HomeScreen 页面代码
import '/core/themes/colors.dart'; import '/core/components/custom_bottom_navigation_bar.dart'; import '/core/components/custom_loader.dart'; import 'components/custom_app_bar.dart'; import 'components/ads_in_overview.dart'; import 'components/ads_in_map.dart'; class HomeScreen extends StatefulWidget { static const routeName = 'home'; HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final PageController pageController = PageController(); int currentPage = 0; @override void dispose() { super.dispose(); pageController.dispose(); } @override Widget build(BuildContext context) { //TODO: there is a custom drawer for filters opened from the search icon button in the custom app bar (not designed yet) return SafeArea( child: Scaffold( appBar: CustomAppBar(), body: PageView( controller: pageController, physics: NeverScrollableScrollPhysics(), allowImplicitScrolling: false, children: [ AdsInMap(), AdsInOverview(), ], ), floatingActionButton: FloatingActionButton.extended( onPressed: () { pageController.animateToPage( currentPage == 0 ? 1 : 0, duration: Duration(milliseconds: 500), curve: Curves.easeInOut, ); setState(() { currentPage = currentPage == 0 ? 1 : 0; }); }, label: Icon( currentPage == 0 ? Icons.format_list_bulleted : Icons.location_on_outlined, ), backgroundColor: Colours.kAccentColor, foregroundColor: Colours.kPrimaryColor, ), bottomNavigationBar: const CustomBottomNavigationBar( selectedTabItemIndex: 0, ), ), ); } }
AdsInMap 组件代码(包含Google Maps)
import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:sizer/sizer.dart'; import 'package:toggle_switch/toggle_switch.dart'; import '/core/themes/colors.dart'; class AdsInMap extends StatefulWidget { const AdsInMap({super.key}); @override State<AdsInMap> createState() => _AdsInMapState(); } class _AdsInMapState extends State<AdsInMap> with AutomaticKeepAliveClientMixin{ int toggleButtonIndex = 0; @override bool get wantKeepAlive => true; //TODO: remove fake data when loading from an API //TODO: the custom marker needs changes Set<Marker> customMarkers = {}; GoogleMapController? controller; /*Future<void> initCustomMarkers() async { final jsonString = await rootBundle.loadString('assets/fake_data/ads.json'); final json = jsonDecode(jsonString); final ads = json['listings']; Set<Marker> newCustomMarkers = {}; if(context.mounted){ for (Map<String, dynamic> ad in ads) { MoneyFormatter formatter = MoneyFormatter( amount: (ad['price'] as int).toDouble(), settings: MoneyFormatterSettings( compactFormatType: CompactFormatType.short), locale: context.locale, ); debugPrint('start creating markers'); newCustomMarkers.addLabelMarker( LabelMarker( label: formatter.output.compactNonSymbol, markerId: MarkerId('${ad['id']}'), position: LatLng(ad['location']['lat'], ad['location']['lng']), ), ); *//*customMarkers.add( Marker( markerId: MarkerId('${ad['id']}'), position: LatLng(ad['location']['lat'], ad['location']['lng']), icon: await CustomMarkerIcon( price: formatter.output.compactNonSymbol, ).toBitmapDescriptor( logicalSize: const Size(1000, 350), imageSize: const Size(1000, 350), ), ), );*//* } setState(() { customMarkers = newCustomMarkers; }); } }*/ @override Widget build(BuildContext context) { return Stack( children: [ //TODO: edit this to be a PageView GoogleMap( myLocationEnabled: true, mapType: MapType.normal, zoomControlsEnabled: false, myLocationButtonEnabled: false, initialCameraPosition: CameraPosition( target: LatLng( 24.774265, 46.738586, ), zoom: 12.0, ), onMapCreated: ((mapController) { setState(() { controller = mapController; }); }), markers: {}, ), Positioned( top: 20.0, left: 8.w, child: ToggleSwitch( minWidth: 28.w, minHeight: AppBar().preferredSize.height, fontSize: 14.sp, initialLabelIndex: toggleButtonIndex, dividerColor: Colours.kPrimaryColor, activeBgColor: const [Colours.kAccentColor], activeFgColor: Colours.kPrimaryColor, inactiveBgColor: Colours.kPrimaryColor, inactiveFgColor: Colours.kAccentColor, centerText: true, totalSwitches: 3, labels: [ tr('main.home.sale'), tr('main.home.rent'), tr('main.home.daily'), ], onToggle: (index) {}, ), ), ], ); } }
修复方案
1. 修正 AutomaticKeepAliveClientMixin 用法
使用AutomaticKeepAliveClientMixin时,必须在build方法中调用super.build(context),否则会导致组件状态异常,进而引发布局渲染错误:
@override Widget build(BuildContext context) { super.build(context); // 必须添加这一行 return Stack( // ... 原有代码 ); }
2. 约束Google Maps的布局尺寸
给Google Maps包裹Expanded或ConstrainedBox,确保它在PageView中有明确的布局约束,避免无限制缩放:
Expanded( child: GoogleMap( // ... 原有地图配置 ), )
3. 调整Sizer字体适配逻辑
14.sp的字体大小在地图组件环境下可能出现异常缩放,建议替换为基于MediaQuery的固定字体大小,或者调整Sizer的全局配置:
fontSize: MediaQuery.of(context).textTheme.bodyMedium?.fontSize ?? 14,
4. 优化地图控制器状态更新
onMapCreated中的setState可以简化,避免不必要的重绘:
onMapCreated: ((mapController) { controller = mapController; // 无需调用setState,因为controller是局部变量,不影响UI渲染 }),
5. 延迟初始化标记(若后续启用)
如果需要加载自定义标记,建议在initState中异步初始化,并用FutureBuilder处理,避免阻塞UI渲染:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { initCustomMarkers(); }); }
内容的提问来源于stack exchange,提问作者Haya Hesham Abdel-azim
相关产品推荐
相关产品推荐

