Skip to content

[google_maps_flutter][iOS] Info window disappears when updating marker icon #167459

@benji-farquhar

Description

@benji-farquhar

The marker info window disappears when updating the marker icon on iOS.

Even on the latest which has a fix for iOS marker not showing (without changing the marker icon though).

I'm on google_maps_flutter: ^2.12.1.

See this comment, I was discussing this bug on #159471, which is a seperate issue that is fixed. As many people were saying, there was a fix to use specific versions of google_maps_flutter and google_maps_flutter_ios, that did not resolve this issue. Contrary to what the other guy said about his code sample updating the marker icon with info window displaying, it does not display the info window.

Steps to reproduce

  1. Add the marker icons to "assets" with the name "selected.png" and "unselected.png"

Image
Image

  1. Run this app on iOS.
  2. Tap on the markers.
  3. Observe the info window does not show.
  4. Comment out this line: // setSelectedMarker(markerId);
  5. Tap on the markers.
  6. Observe the info window showing, but obviously the marker icon doesn't change.

Expected results

The info window stays open, even when the marker icon image changes.

Actual results

The info window does not show when the icon image changes. It does show when we do not update the marker icon.

Code sample

Code sample

main.dart:

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyWidget(),
    );
  }
}

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  List<Marker> markers = [];
  GoogleMapController? googleMapController;
  Marker? selectedMarker;
  late BitmapDescriptor defaultPin;
  late BitmapDescriptor selectedPin;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: GoogleMap(
          markers: markers.toSet(),
          initialCameraPosition: const CameraPosition(
            target: LatLng(41.00024866867318, 29.0257125104099),
            zoom: 8.4746,
          ),
          onMapCreated: (controller) {
            googleMapController = controller;
          },
        ),
      ),
    );
  }

  Future<void> getInitialMarkers() async {
    defaultPin = await icon('assets/unselected.png');
    selectedPin = await icon('assets/selected.png');

    markers = [
      Marker(
        markerId: const MarkerId('1'),
        position: const LatLng(40.98497470084764, 29.069472563574063),
        icon: defaultPin,
        infoWindow: const InfoWindow(title: 'title 1', snippet: 'snippet 1'),
        onTap: () => onTap(const MarkerId('1')),
      ),
      Marker(
        markerId: const MarkerId('2'),
        position: const LatLng(40.83428951050001, 29.481392650987797),
        icon: defaultPin,
        infoWindow: const InfoWindow(title: 'title 2', snippet: 'snippet 2'),
        onTap: () => onTap(const MarkerId('2')),
      ),
    ];
    refresh();
  }

  Future<BitmapDescriptor> icon(String path) async {
    final ByteData data = await rootBundle.load(path);
    final Codec codec = await instantiateImageCodec(
      data.buffer.asUint8List(),
      targetWidth: 100,
    );
    final FrameInfo frameInfo = await codec.getNextFrame();
    final byteData = await frameInfo.image.toByteData(format: ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List());
  }

  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) {
      getInitialMarkers();
    });
  }

  void onTap(MarkerId markerId) {
    googleMapController?.showMarkerInfoWindow(markerId);

    if (selectedMarker?.markerId == markerId) {
      // Deselect marker if it's already selected
      setSelectedToNormal();
      refresh();
      return;
    }

    setSelectedMarker(markerId);
    refresh();
  }

  void refresh() {
    setState(() {});
  }

  void setSelectedMarker(MarkerId markerId) {
    // Reset previously selected marker if exists
    if (selectedMarker != null) {
      setSelectedToNormal();
    }

    final markerIndex = markers.indexWhere((m) => m.markerId == markerId);
    if (markerIndex != -1) {
      final marker = markers[markerIndex];
      markers[markerIndex] = marker.copyWith(
        iconParam: selectedPin,
      );
      selectedMarker = markers[markerIndex];
    }
  }

  void setSelectedToNormal() {
    if (selectedMarker == null) return;

    final markerIndex = markers.indexWhere((m) => m.markerId == selectedMarker!.markerId);
    if (markerIndex != -1) {
      final marker = markers[markerIndex];
      markers[markerIndex] = marker.copyWith(
        iconParam: defaultPin,
      );
      selectedMarker = null;
    }
  }
}

pubspec.yaml:

name: info_window_bug
description: "A new Flutter project."

publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ^3.8.0-278.1.beta

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^2.12.1
  cupertino_icons: ^1.0.8

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0

flutter:
  uses-material-design: true

  assets:
    - assets/unselected.png
    - assets/selected.png

AppDelegate.swift:

import UIKit
import Flutter
import GoogleMaps

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey("YOUR_API_KEY_HERE")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Screenshots or Video

Screenshots / Video demonstration

When not changing marker icon:

Simulator.Screen.Recording.-.iPhone.16.-.2025-04-21.at.12.22.08.mp4

When changing marker icon:

Simulator.Screen.Recording.-.iPhone.16.-.2025-04-21.at.12.23.13.mp4

Logs

No response

Flutter Doctor output

Doctor output
[✓] Flutter (Channel beta, 3.32.0-0.1.pre, on macOS 15.3.2 24D81 darwin-arm64, locale en-GB) [371ms]
    • Flutter version 3.32.0-0.1.pre on channel beta at /Users/Benji/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision eeb81b9a8a (9 days ago), 2025-04-11 12:11:52 -0700
    • Engine revision 72ee26e314
    • Dart version 3.8.0 (build 3.8.0-278.1.beta)
    • DevTools version 2.45.0

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.1) [3.3s]
    • Android SDK at /Users/Benji/Library/Android/sdk
    • Platform android-35, build-tools 35.0.1
    • ANDROID_HOME = /Users/Benji/Library/Android/sdk
    • ANDROID_SDK_ROOT = /Users/Benji/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 21.0.5+-12932927-b750.29)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.3) [966ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16E140
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [29ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.3) [29ms]
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 21.0.5+-12932927-b750.29)

[✓] IntelliJ IDEA Community Edition (version 2024.2.1) [26ms]
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.99.1) [10ms]
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.108.0

[✓] Connected device (5 available) [6.0s]
    • sdk gphone64 arm64 (mobile)                • emulator-5554                        • android-arm64  • Android 15 (API 35) (emulator)
    • Benji’s iPhone 13 mini (wireless) (mobile) • 00008110-001119123C7B801E            • ios            • iOS 18.3.2 22D82
    • iPhone 16 (mobile)                         • 8954A785-6366-40A0-BD9D-7789B1F26A1B • ios            • com.apple.CoreSimulator.SimRuntime.iOS-18-4 (simulator)
    • macOS (desktop)                            • macos                                • darwin-arm64   • macOS 15.3.2 24D81 darwin-arm64
    • Chrome (web)                               • chrome                               • web-javascript • Google Chrome 135.0.7049.96

[✓] Network resources [1,596ms]
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    found in release: 3.29Found to occur in 3.29found in release: 3.32Found to occur in 3.32has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: mapsGoogle Maps pluginpackageflutter/packages repository. See also p: labels.platform-iosiOS applications specificallyr: fixedIssue is closed as already fixed in a newer versionteam-iosOwned by iOS platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions