You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:23:12