Asset.loadAsync image density issue

#1

Hi guys,
Im getting something strange here with assets through Asset.loadAsync and with their image densities.

Note: I have 3 different images according each density (look in snack for these files).

Code in snack:

Full code (without images):

import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { AppLoading, Asset, MapView } from 'expo';

const REGION = {
  latitude: 37.78825,
  longitude: -122.4324,
  latitudeDelta: 0.0922,
  longitudeDelta: 0.0421,
};

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      initialRegion: REGION,
      animatedRegion: new MapView.AnimatedRegion(REGION),
      isLoadingComplete: false,
    };
  }

  _loadResourcesAsync = async () => {
    return Promise.all([
      Asset.loadAsync([
        require('./assets/images/marker-truck-ongoing.png')
      ]),
    ]);
  };

  _handleLoadingError = error => {
    // In this case, you might want to report the error to your error
    // reporting service, for example Sentry
    console.warn(error);
  };

  _handleFinishLoading = () => {
    this.setState({
      isLoadingComplete: true
    });
  };

  render() {
    const {
      initialRegion,
      animatedRegion,
      isLoadingComplete,
    } = this.state;
    if (!isLoadingComplete) {
      return (
        <AppLoading
          startAsync={this._loadResourcesAsync}
          onError={this._handleLoadingError}
          onFinish={this._handleFinishLoading}
        />
      );
    }
    return (
      <View style={styles.container}>
        <MapView style={styles.map} initialRegion={initialRegion}>
          <MapView.Marker.Animated
            coordinate={animatedRegion}
            centerOffset={{ x: 0, y: -18 }}
            image={require('./assets/images/marker-truck-ongoing.png')}
          />
        </MapView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  map: {
    ...StyleSheet.absoluteFillObject,
  },
});

The problem I’m having is that if I use the image directly without using Asset.loadAsync it works correctly, otherwise the image does not respect the size set in iOS, look the following captures:

with Asset.loadAsync:

without (this was the expected result):

If you want to try the code by yourself, just modify the isLoadingComplete mark to use the cache or not (with the mark in true, do not use Asset.loadAsync)

Any help will be welcome, I am afraid that the Expo Asset.loadAsync is the cause of this issue,

Thanks !!!

0 Likes

#2

@janic something related with https://github.com/expo/xdl/pull/24?

0 Likes

#3

The same issue from SDK 25: Custom map-markers are now HUGE on iOS, any update @andrioid, im dealing with this insane issue :exploding_head:

0 Likes

#4

I am also very frustrated with the quality of react-native-maps right now. There are iOS specific bugs, Android specific bugs and the workaround for these bugs conflict in ways that make my head :exploding_head:

What I did to get our app out, was to stop preloading those images. But, my plan is to make the markers Platform specific (.ios.js, .android.js) and apply each workaround there.

I’m not sure if the Expo team can help with this one, but it sure would be nice.

0 Likes

#5

Hey @outatime,
Your snack is giving me the expected image size when using _loadResourceAsync. Are you still experiencing the issue?

0 Likes

#6

Yup the snack works as expected you must run on physical iOS device or simulator.

0 Likes

#7

Quick update. I updated to SDK 26 today and that bug is back for me too. With or without prefetching. I’ve double checked 2x 3x files, and they are correct.

I’ve also tried upgrading and downgrading exp before creating the bundle. No effect.

Not reproducible in the Expo client. Only as a standalone build.

0 Likes

#8

@andrioid im finally using the following “hack” with SDK 26 and im getting work in android / ios with prefetch support.

Prefech phase:

const imageAssets = Asset.loadAsync([
  require('./assets/images/marker-car-exceeded.png'),
  require('./assets/images/marker-car-ongoing.png'),
  require('./assets/images/marker-car-stale.png'),
  require('./assets/images/marker-car.png'),
]);

Marker component:

import React from 'react';
import PropTypes from 'prop-types';
import { MapView } from 'expo';
import { Image } from 'react-native';

export default class DeviceMarker extends React.PureComponent {

  static propTypes = {
    coordinate: PropTypes.object.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      initialRender: true
    };
  }

  render() {
    const {
      coordinate,
    } = this.props;
    return (
      <MapView.Marker.Animated
        coordinate={coordinate}
        centerOffset={{ x: 0, y: -18 }}
      >
        <Image
          source={return require('./assets/images/marker-car-exceeded.png')}
          onLayout={() => this.setState({ initialRender: false })}
          key={`${this.state.initialRender}`}
        />
      </MapView.Marker.Animated>
    );
  }
}

Component usage:

<MapView
  ref={ref => (this._mapRef = ref)}
  style={styles.map}
  initialRegion={initialRegion}
>
  <DeviceMarker
    coordinate={animatedRegion}
  />
</MapView>

I hope you find it useful

0 Likes

#9

Thank you @outatime! I’ll try it out. Does this work on Android 7+ ?

I had to remove my component from Markers because Android 7 didn’t render them.

But currently, my markers just crash on Android - so I look forward to see if this maybe works on both platforms. Fingers crossed.

0 Likes

#10

@andrioid I tested up to version 7.0.0 (API 24) and worked perfectly. I couldn’t try higher versions yet, if you have any feedback it will be welcome.

0 Likes

#11

@outatime Have you tried this on Android 7.1.1 yet? Because it renders blank on my Nokia 3 test phone.

0 Likes

closed #12

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.

0 Likes