React Native Maps: Markers image doesn't show using Custom Marker in react-native-maps
Asked Answered
T

10

17

I'm using react-native-maps but I faced a problem that after a lot of googling without answer makes me ask it here. I'm trying to use Custom Marker for the marker in the map as the following picture

enter image description here

  • as I searched I found out that needed to use Custom Marker to accomplish the maker's design, then I created a Custom Marker component

    import React, { Component } from "react";
    import { View } from "react-native";
    import {
    Text,
    Left,
    Right,
    Thumbnail,
    } from "native-base";
    const defaultEmployeeLogo = require("../../../assets/defualtEmployee.png");
    class CustomMarker extends Component {
    render() {
        return (
        <View style={{ flexDirection: 'row', width: 140, height: 60, 
          borderRadius: 70, backgroundColor: 'orange' }}>
            <Left>
                <Thumbnail source={defaultEmployeeLogo} />
            </Left>
            <Right>
                <Text style={{
                    color: '#fef',
                    fontSize: 13,
                    paddingBottom: 2,
                    fontFamily: 'Roboto',
                    alignItems: 'center',
                    paddingRight: 10
                }}>Mohammad</Text>
            </Right></View >);
       }
    }
    export default CustomMarker;
    

when I use CustomMarker.js class solely it works fine and it shows the image but when I use it as the marker custom view it doesn't show the image

enter image description here

I don't know why it can't render the image with Custom Marker in android. and here is my code where I'm using map, markers and custom marker class

return (
  <View style={styles.map_container}>
    <MapView
      style={styles.map}
      customMapStyle={customrMapStyle}
      region={{
        latitude: this.state.region.latitude,
        longitude: this.state.region.longitude,
        latitudeDelta: 0.4,
        longitudeDelta: 0.41,
      }} >
      {
        coordinationData.map(function (marker, i) {

          let lat = marker.latLang.latitude;
          let lang = marker.latLang.longitude;
           <MapView.Marker
            key={i}
            coordinate={
              {
                latitude: lat,
                longitude: lang,
                latitudeDelta: 0.4,
                longitudeDelta: 0.41
              }
            }
            title={marker.title}
            description={marker.description}

          >
            <CustomMarker />
          </MapView.Marker>
        })}
    </MapView>
  </View>

any kind of help would be appreciated.

Thingumajig answered 19/8, 2018 at 7:7 Comment(0)
I
8

Use SVG for this https://github.com/react-native-community/react-native-svg

<Marker
    coordinate={{
        longitude: lang,
        latitude: lat,
    }}
>
    <View style={{
        flexDirection: 'row', width: 100, height: 30,
        backgroundColor: 'orange'
    }}>
        <Svg
            width={40} height={30}>
            <Image
                href={url}
                width={40}
                height={30}
            />
        </Svg>
        <View
            style={{
                flexDirection: 'column'

            }}
        >
            <Text
                style={{
                    marginLeft: 2,
                    fontSize: 9,
                    color: '#ffffff',
                    fontWeight: 'bold',
                    textDecorationLine: 'underline'
                }}
            >{marker.title}</Text>
            <Text
                style={{
                    marginLeft: 2,
                    fontSize: 9,
                    color: '#ffffff',
                    fontWeight: 'bold',
                    textDecorationLine: 'underline'
                }}
            >{marker.description}</Text>
        </View>
    </View>
</Marker>
Irremissible answered 3/10, 2018 at 6:28 Comment(0)
I
6

My problem was solved right now.

I hope your problem will be solved.

This is my clean code:

import React, {Component} from 'react';
import {ImageBackground, Text} from 'react-native';
import {Marker} from 'react-native-maps';

export default class CustomMarker extends Component {
    state = {
        initialRender: true
    }

    render() {
        return (
            <Marker
              //...
            >
                <ImageBackground
                    source={require('../assets/cluster3_mobile.png')}>

                    // *** These lines are very important ***
                    onLoad={() => this.forceUpdate()}
                    onLayout={() => this.setState({initialRender: false})}
                    key={`${this.state.initialRender}`}
                    >
                    

                    // **** This line is very very important ****
                    <Text style={{width: 0, height: 0}}>{Math.random()}</Text>

                </ImageBackground>
            </Marker>
        );
    }
}
Irremissible answered 19/8, 2018 at 10:35 Comment(7)
I think you must add style to ImageBackgrund , at least running in android shows this error. @Mahdi BashirpourThingumajig
Instead of using native-base, test this straightforward my code. Maybe it's a problem. Or else test the component code somewhere other than the map to see if it works there @ThingumajigIrremissible
If the whole thing works out of a map , then it is likely that the map with Component native-base is problematic @ThingumajigIrremissible
sorry this is not the issue, I think the problem is Android .@Mahdi BashirpourThingumajig
So use exactly my codes. And rest assured that it will be true because I've tried it @ThingumajigIrremissible
Have u tried your codes on Android Phone? @Mahdi BashirpourThingumajig
and it worked? if yes would u share screenshot in order to show my employer @Mahdi BashirpourThingumajig
S
3

as of Oct 2019, the image can be displayed in the marker as along as the tracksViewChanges is set to true. I use FastImage but the general idea is to set tracksViewChanges to true and then to false as soon as the image is loaded so that there won't be any performance issue.

export const UserMapPin = props => {
  const [trackView, setTrackView] = useState(true);

  function changeTrackView() {
    setTrackView(false);
  }

  return (
    <Marker
      tracksViewChanges={trackView}
      coordinate={props.coordinates}>
      <View style={styles.imageIconContainer}>
          <FastImage
            onLoadEnd={changeTrackView}
            style={styles.someImageStyle}
            source={{
              uri: props.imageURI,
            }}
            resizeMode={FastImage.resizeMode.cover}
          />
      </View>
    </Marker>
  );
};
Sixtasixteen answered 19/12, 2019 at 6:18 Comment(0)
I
2

I had the same problem.

When you first load an application, the image does not show, but for later loading, this problem is resolved and show image.

Just enough after the image is loaded call this.forceUpdate()

const defaultEmployeeLogo = require("../../../assets/defualtEmployee.png");

<Image source={defaultEmployeeLogo} onLoad={() => this.forceUpdate()}>
    <Text style={{width:0, height:0}}>{Math.random()}</Text>
</Image>

You can track this:

https://github.com/react-community/react-native-maps/issues/924

Irremissible answered 19/8, 2018 at 8:47 Comment(7)
I'm loading the image neither from web server nor AsynStoage, it's just in my local project.@Mahdi BashirpourThingumajig
No. You do not get an image from the web. Your image is local. const defaultEmployeeLogo = require("../../../assets/defualtEmployee.png");Irremissible
It does not matter at all. Please try this this.forceUpdate() when loaded image or screenIrremissible
beside that if I use image as a tag inside Marker it works properly,but I need to use it in my Custom View for marker since I need to use text with a custom view a long side with iamge.Thingumajig
This worked for me #51915853 @abdu4Irremissible
hmm, so why it doesn't work for me? which platform u are running the APP android or iOS? @Mahdi BashirpourThingumajig
running on android platform @ThingumajigIrremissible
S
2

@Mahdi Bashirpour solution works for me. just upgrading above answer.

Other Images stop working if we import 'Image' from 'react-native-svg'

My solution is below.

import {Image} from 'react-native';   // for other images in our render method.
import { Image as Imagesvg } from 'react-native-svg';

<Marker
   coordinate={marker.latlng}
   title={marker.title}
 >

<View style={{ height: 90, width: 90, backgroundColor: 'orange' }}>
      <Svg width={90} height={90}}>
        <Imagesvg href={marker_g} width={90} height={90} />  // Local Images
       <Imagesvg href={{uri:url}} width={90} height={90} />   //Server images
    </Svg>
</View>
</Marker>

Use 'Imagesvg' for marker image. It's working for me on android 7 and 8. React native version '0.55.3'

Schleswig answered 11/10, 2018 at 9:23 Comment(0)
I
1

This is another example

class PinMarker extends Component {
  state = {
    initialRender: true
  }
  render() {
    return (
      <MapView.Marker coordinate={coordinate}>
        <Image
          source={...}
          onLayout={() => this.setState({ initialRender: false })}
          key={`${this.state.initialRender}`}
        />
      </MapView.Marker>
    )
  }
}
Irremissible answered 19/8, 2018 at 9:15 Comment(3)
really appreciate your responses, but again the same result, the map loads but the image is not shown.Thingumajig
any other idea? @Mahdi BashirpourThingumajig
Because I myself had the same problem, I'm working on it right now. I have come up with good results @abdu4Irremissible
C
1

I Had same problem , from github post

using below(MapView , Image) pattern first load problem will still occour

<MapView.Marker>
    <Image source={img_marker} />
</MapView.Marker>

so adopted below solution : trick is to save current selected marker id in redux

class Map extends React.Component {
render() {
    let {region, markers , markerClick} = this.props;
    const normalMarkerImage = require('../../images/normal_marker.png');
    const selectedMarkerImage = require('../../images/selected_marker.png');
    return !isObjectEmpty(region) && !isObjectEmpty(markers) ? (
        <MapView
            style={styles.map}
            showsUserLocation={true}
            followUserLocation={true}
            zoomEnabled={true}
            region={region}
            paddingAdjustmentBehavior={'automatic'}
            showsIndoors={true}
            showsIndoorLevelPicker={false}
            showsTraffic={false}
            toolbarEnabled={false}
            loadingEnabled={true}
            showsMyLocationButton={true}>
            {markers && markers.length > 0
                ? markers.map((marker, i) => (
                        <MapView.Marker
                            coordinate={{
                                longitude: marker.loc.coordinates[0],
                                latitude: marker.loc.coordinates[1],
                            }}
                            key={`marker-${i}`}
                            style={{height: 20, width: 20}}
                            onPress={e => markerClick(e, marker)}
                            image={
                                this.props.selectedMarker === marker._id
                                    ? selectedMarkerImage
                                    : normalMarkerImage
                            }
                        />
                  ))
                : null}
        </MapView>
    ) : null;
  }
}

component Function

markerClick = async (event, data) => {
    this.props.dispatch(
        setMarkerIconInRedux(this.state.popover.currentData._id)
    );
};

Action

export const setMarkerIconInRedux = where => {
    return {
        type: 'SET_MARKER_ICON',
        _id: where,
    };
};

Redux

export const currentSelectedMarker = (state = {selectedMarker: ''}, action) => 
{
    if (action.type === 'SET_MARKER_ICON') {
        return {selectedMarker: action._id};
    } else if (action.type === 'REMOVE_MARKER_ICON') {
        return {selectedMarker: ''};
    } else {
        return state;
    }
};
Cerise answered 28/8, 2018 at 6:36 Comment(0)
J
1

I solved this issue by replacing 16-bit gamma integer Image with 8-bit gamma integer Image. It can be done in Gimp, once exporting Image select 8bpc RGBA.

Jemma answered 16/1, 2019 at 19:35 Comment(2)
can u please add an example as well?Thingumajig
It is not about coding, it is about replacing Image. Your Image should be in 8-bit gamma integer format.Bucko
O
0

For my case the problem was only with remote Images so I solve it by a hack.

I just put one version of Image with zero width inside Text Component and one version out side Text Component. and suddenly everything's solved.

    <Image
     source={{ uri: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg" }}
     style={styles.companyLogoMarker}
     resizeMode="cover"
     />
     <Text style={styles.markerText}>
        {names?.[0]?.value}
       <Image
           source={{ uri: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg" }}
           style={{width: 0, height: 0}}
           resizeMode="cover"
        />
     </Text>

as of writing this Answer this is a bug in [react native maps][1] and not solved since 2017

Outofdoor answered 5/5, 2020 at 10:37 Comment(0)
L
0

Add your custom marker component inside <View> e.g. <View> your marker custom view </View>. Maybe it will resolve your issue.

Lithe answered 3/11, 2020 at 9:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.