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.

Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
Abdu4
  • 1,269
  • 2
  • 11
  • 19

10 Answers10

7

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>
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
5

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>
        );
    }
}
Community
  • 1
  • 1
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
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>
  );
};
Travalour
  • 93
  • 1
  • 8
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

Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
  • I'm loading the image neither from web server nor AsynStoage, it's just in my local project.@Mahdi Bashirpour – Abdu4 Aug 19 '18 at 09:05
  • No. You do not get an image from the web. Your image is local. const defaultEmployeeLogo = require("../../../assets/defualtEmployee.png"); – Mahdi Bashirpour Aug 19 '18 at 09:09
  • It does not matter at all. Please try this `this.forceUpdate()` when loaded image or screen – Mahdi Bashirpour Aug 19 '18 at 09:10
  • 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. – Abdu4 Aug 19 '18 at 09:11
  • This worked for me https://stackoverflow.com/questions/51915353/react-native-maps-markers-image-doesnt-show-using-custom-marker-in-react-nativ/51916780#51916780 @abdu4 – Mahdi Bashirpour Aug 20 '18 at 06:53
  • hmm, so why it doesn't work for me? which platform u are running the APP android or iOS? @Mahdi Bashirpour – Abdu4 Aug 20 '18 at 06:59
  • running on android platform @Abdu4 – Mahdi Bashirpour Aug 20 '18 at 07:24
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'

krish
  • 3,856
  • 2
  • 24
  • 28
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>
    )
  }
}
Mahdi Bashirpour
  • 17,147
  • 12
  • 117
  • 144
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;
    }
};
vijay
  • 10,276
  • 11
  • 64
  • 79
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.

Vladimír
  • 701
  • 1
  • 7
  • 24
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

TheEhsanSarshar
  • 2,677
  • 22
  • 41
0

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

Prashant Jajal
  • 3,469
  • 5
  • 24
  • 38