react-native-maps: [iOS] Marker icons are too large after assets are bundled during build

Summary

When using the icon or image prop to render a custom marker image on iOS, there is a difference in size of the icon when running locally compared to the final build result when the provided icon has different resolutions. The final build displays the icons much larger than they should be.

The same problem does not occur on Android.

I understand that there is a workaround to simply render an <Image /> as a child of the Marker, however this isn’t acceptable since it is not as performant for a large number of markers compared to using the icon prop.

Reproducible sample code

import { useEffect, useState } from "react";
import { Image } from "react-native";
import { Asset } from "expo-asset";
import MapView, { Marker } from "react-native-maps";

export default function App() {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    (async () => {
      await Promise.all([...cacheImages()]);
      setIsReady(true);
    })();
  }, []);

  if (!isReady) {
    return null;
  }

  return (
    <MapView
      style={{ flex: 1 }}
      initialCamera={{
        center: { latitude: -33.8688, longitude: 151.2099 },
        zoom: 3,
        heading: 0,
        pitch: 0,
      }}
      provider="google"
    >
      <Marker
        coordinate={{ latitude: -33.8688, longitude: 151.2099 }}
        icon={require("./src/assets/pin.png")}
        anchor={{ x: 0.5, y: 0.5 }}
      />
    </MapView>
  );
}

/**
 *
 * https://docs.expo.dev/archive/classic-updates/preloading-and-caching-assets/#pre-loading-and-caching-assets
 */
function cacheImages() {
  return [require("./src/assets/pin.png")].map((image) => {
    if (typeof image === "string") {
      return Image.prefetch(image);
    } else {
      return Asset.fromModule(image).downloadAsync();
    }
  });
}

Steps to reproduce

I have put together a sample project where the problem can be reproduced here.

The caching mechanism in the sample code simulates what the result of asset bundling during local development to help with reproducing the problem.

And it’s important to have different resolutions of the image (i.e. @2x @3x)

Expected result

The Marker should show the correct size in the final release build when using the icon prop. expected

Actual result

The Marker is showing a larger icon size in the final release build when using the icon prop. actual

React Native Maps Version

1.3.2

What platforms are you seeing the problem on?

iOS (Google Maps)

React Native Version

0.70.5

What version of Expo are you using?

SDK 47

Device(s)

iPhone 13, iOS simulator

Additional information

No response

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 1
  • Comments: 19

Most upvoted comments

I found that placing scaled images like FileName@3x.png alongside FileName.png makes image sizes consistent across builds. I didn’t need to import the @3x variant in my code.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If the issue remains relevant, simply comment Still relevant and the issue will remain open. Thank you for your contributions.

As a workaround, dynamically choosing between the image prop and a child component based on platform works for us. I also had to add tracksViewChanges={false} since there’s a large slowdown on Android by default (issue #4700)

<MapView ...>
  {items?.map((item) => {
    const image =
      selectedItem?.id === item.id ? IconMarkerSelected : IconMarker
    return (
      <Marker
        ...
        tracksViewChanges={false}
        image={Platform.OS === "ios" ? undefined : image}
      >
        {Platform.OS === "ios" ? <Image source={image} /> : null}
      </Marker>
    )
  })}
</MapView>

Still relevant

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If the issue remains relevant, simply comment Still relevant and the issue will remain open. Thank you for your contributions.