Dynamically rendered RasterLayer does not display on Android
Hello, I am having an issue that seems to be specific to Android when trying to dynamically render multiple RasterLayer elements. Specifically, the layers do not display on the map, even though I have confirmed that the render function runs (and it works/displays just fine on iOS). If I force a re-draw of MapLibreGL.MapView the layers will show up properly, but this resets the map camera location and flashes to white which is not a great user experience. Here is some example code:
...
const layerEls = []
timeMatchTimes.forEach((timeToMatch, i) => {
let isVisible = false
if (i === sliderValue) {
isVisible = true
}
let timeIndex = findClosestTimeIndex(dayjs.utc(timeToMatch), layerData.times)
let time = layerData.times[timeIndex]
let timeURLStr = dayjs.utc(time).format("YYYYMMDD_HHmmss")
let layerID = layerData.id + timeURLStr
let sourceID = layerData.id + timeURLStr + "source"
let rasterSourceProps = {
id: sourceID,
tileUrlTemplates: [
`https://tiledata.satsquatch.com/tilesdata/${sat+"_"+band}/${sector}/${timeURLStr}/{z}/{x}/{y}.png`,
],
tileSize: 256,
tms: true
};
layerEls.push(
<MapLibreGL.RasterSource key={sourceID} {...rasterSourceProps}>
<MapLibreGL.RasterLayer
key={layerID}
id={layerID}
sourceID={sourceID}
style={{rasterOpacity: isVisible ? 0.8 : 0.0, visibility: isVisible ? "visible" : "none", rasterFadeDuration: 0, rasterOpacityTransition: {duration: 0, delay: 0}}} //
/>
</MapLibreGL.RasterSource>
);
});
return (
<>
{layerEls}
</>
)
Is there something special I need to be doing to get this to work on android as expected?
Environment
- Platform: Android
- OS version: Android 13
- Device type: Pixel 5
- Emulator or Simulator: no
- Development OS: Windows 11/macOS
-
@maplibre/maplibre-react-nativeVersion: 10.0.0-alpha.24 -
react-nativeVersion: 0.74.5 -
expoVersion: 51.0.39
Additional context
I am using Expo development builds on physical devices (ios/android) as well as emulators
Here is a complete example of what I am referring to: https://github.com/atkingtornado/testrasterlayers
when the "times" state gets updated on button press, the rasterlayer(s) do not render accordingly (https://github.com/atkingtornado/testrasterlayers/blob/master/app/index.tsx)
Was able to reproduce, can only make it visible with changing the key of MapView on Android.
Adapted your example to be used within the BugReport template:
import MapLibreGL from "@maplibre/maplibre-react-native";
import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
MapLibreGL.setAccessToken(null);
const styles = StyleSheet.create({
map: {
flex: 1,
alignSelf: "stretch",
},
container: {
position: "absolute",
bottom: 90,
right: 20,
zIndex: 9999,
},
button: {
padding: 10,
backgroundColor: "white",
borderRadius: 5,
borderColor: "rgba(25, 118, 210, 0.2)",
borderWidth: 1,
},
icon: {
width: 32,
height: 32,
},
});
const sat = "GOES16";
const band = "14";
const sector = "CONUS";
export default function Index() {
const [times, setTimes] = useState([]);
const onPress = async () => {
console.log("Press " + times.length);
if (times.length === 0) {
console.log("we try....");
try {
const response = await fetch(
"https://tiledata.satsquatch.com/tilesdata/GOES16_14_CONUS.json",
);
console.log("We got response!");
if (!response.ok) {
throw new Error("Network response was not ok " + response.statusText);
}
console.log("Get JSON");
const data = await response.json();
console.log(JSON.stringify(data));
console.log(JSON.stringify(data.times.slice(-10)));
setTimes(data.times.slice(-10));
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
}
} else {
setTimes([]);
}
};
console.log("Showing: " + times.length);
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<IconButton onPress={onPress} />
<MapLibreGL.MapView
key={1}
style={styles.map}
logoEnabled={false}
compassEnabled
attributionPosition={{ top: 18, left: 18 }}
styleURL="https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
>
{times.map((timeURLStr, i) => {
console.log("rendering " + i);
const isVisible = i === 0;
const sourceID = sat + timeURLStr + "source";
const layerID = sat + timeURLStr + "layer";
return (
<MapLibreGL.RasterSource
key={sourceID}
id={sourceID}
tileUrlTemplates={[
`https://tiledata.satsquatch.com/tilesdata/${sat + "_" + band}/${sector}/${timeURLStr}/{z}/{x}/{y}.png`,
]}
tms
tileSize={256}
>
<MapLibreGL.RasterLayer
key={layerID}
id={layerID}
sourceID={sourceID}
style={{
rasterOpacity: isVisible ? 0.8 : 0.0,
visibility: isVisible ? "visible" : "none",
rasterFadeDuration: 0,
rasterOpacityTransition: { duration: 0, delay: 0 },
}}
/>
</MapLibreGL.RasterSource>
);
})}
</MapLibreGL.MapView>
</View>
);
}
type IconButtonProps = {
onPress: () => void;
};
const IconButton = ({ onPress }: IconButtonProps) => {
return (
<View style={styles.container}>
<TouchableOpacity onPress={onPress} style={styles.button}>
<Text>Test</Text>
</TouchableOpacity>
</View>
);
};
I've done a quick bit of Googling, and this may be fixed in a newer version.can anyone confirm if this is still a problem, with the latest release?