modal shows in ios but not on android? react-native-maps marker onPress

Viewed 39

Edit: I think i figured one part out - the child components (markers+modal) doesn't re-render the parent (map screen) when updated... It's funny though that it works in iOs.

Edit pt. 2 : Solved it! I lifted the function that opens to modal to parent and used lifted states to access it. Then it worked. Funny that it works without that in iOS but not in android, should be the same.


Question:

Im creating a game where you can open clues if you are in the right geographical place. It works in IOS, but in Android the modal does not open. It should open even if user is in correct geo place or not. If i set state "setModalVisible" to true I can see the modal. I can also see that the state changes to true when a clue/marker is clicked. Why doesnt the modal show? I have noticed that the "while" loop does not run (only when in android), but I still get the same error after I remove the while-loop and only have the location as await. Please help me!

This is the component in which the markers and the modal is:

...import ...

export function MapMarkersClues({ open }) {
  ///////////////
  /// STATES ///
  //////////////
  const [isLoading, setIsLoading] = useState(true);
  const [isLoadingLocation, setisLoadingLocation] = useState(true);
  const [modalVisible, setModalVisible] = useState(false);
  const [modalUpdate, setModalUpdate] = useState(false);
  const [modalText, setModalText] = useState(
    "Du måste gå närmare för att öppna ledtråden"
  );
  const [modalImage, setModalImage] = useState(Images.gameone.LockedClue);
  const [modalImageTxt, setModalImageTxt] = useState("");
  const [openedClue, setopenedClue] = useState(false);
  const [markers, setMarkers] = useState([]);
  const [markermodal, setmarkerModal] = useState([]);
  const [CLUES, setClues] = useState(false);
  const [cluesChanged, setCluesChanged] = useState(false);

  ////////////////////
  /// STORAGE GET ///
  //////////////////
  const getData = async () => {
    while (isLoading === true) {
      try {
        const jsonValue = await AsyncStorage.getItem("@clues_game_one");
        setClues(JSON.parse(jsonValue) || CluesData);
        if (CLUES != null && CLUES != false) {
          setIsLoading(false);
        }
      } catch (e) {
        console.log("error occured in getData:" + e);
      }
    }
  };
  useEffect(() => {
    getData();
  });

  /////////////////
  /// FUNCTIONS ///
  /////////////////
  // Getting Location when clue is opened
  async function getLocation() {
    while (isLoadingLocation === true) {
      try {
        setModalText("Ledtråden laddas...");
        setModalImageTxt("");
        setModalImage(Images.gameone.Otto);
        const Loc = await Location.getCurrentPositionAsync({
          accuracy: Location.Accuracy.Low,
        });
        if (Loc != undefined) {
          console.log(modalVisible);
          setisLoadingLocation(false);
          return Loc;
        }
      } catch (e) {
        console.log(e);
      }
    }
  }
  

// I can see here that the state changes as expected
  useEffect(() => {
    console.log(modalVisible);
  }, [modalVisible]);

  // Checking if clue should open or not and returning correct values.


  const openClue = async (item) => {
    setModalVisible(true);

    if (item.icon === "unlock") {
      setModalImage(Images.gameone[item.img]);
      setModalImageTxt(item.imgTitle);
      setModalText(item.text);
    } else {
      const Loc = await getLocation();
      if (Loc != undefined) {
        if (
          Loc.coords.latitude >= item.lat - 0.00025 &&
          Loc.coords.latitude <= item.lat + 0.00025 &&
          Loc.coords.longitude >= item.long - 0.00025 &&
          Loc.coords.longitude <= item.long + 0.00025
        ) {
          setModalImage(Images.gameone[item.img]);
          setModalImageTxt(item.imgTitle);
          setModalText(item.text);
          item.icon = "unlock";

          const storeData = async (value) => {
            try {
              const jsonValue = JSON.stringify(value);
              await AsyncStorage.setItem("@clues_game_one", jsonValue);
            } catch (e) {
              console.log(e);
            }
          };
          storeData(CLUES);
          setCluesChanged(true);
        } else if (item.icon == "lock") {
          setModalText("Du måste gå närmare för att öppna ledtråden");
          setModalImageTxt("");
          setModalImage(Images.gameone.LockedClue);
        } else if (item.icon == "info-circle") {
          setModalText("Du måste gå närmare för att läsa faktatexten");
          setModalImageTxt("");
          setModalImage(Images.gameone.LockedClue);
        }
        setModalUpdate(true);
      }
    }
  };
  // closes modal and changes states back to default.
  const closeClue = () => {
    console.log("close it");
    setModalVisible(false);
    setModalUpdate(false);
    setisLoadingLocation(true);
    if (cluesChanged) {
      setopenedClue(!openedClue);
      setCluesChanged(false);
    }
  };

  //mapping out map-markers
  useEffect(() => {
    if (isLoading === false) {
      setMarkers(
        CLUES?.map((mark) => {
          return (
            <Marker
              key={mark.key}
              keyExtractor={(mark) => mark.key.toString()}
              coordinate={{
                latitude: mark.lat,
                longitude: mark.long,
              }}
              onPress={() => openClue(mark)}
            >
              <FontAwesome name={mark.icon} size={29} color={mark.color} />
            </Marker>
          );
        })
      );
    }
  }, [openedClue, isLoading]);

  //MODAL
  useEffect(() => {
    setmarkerModal(() => {
      return (
        <View style={styles.centeredView}>
          <Modal
            animationType='slide'
            transparent={true}
            visible={modalVisible}
            onRequestClose={() => {
          setModalVisible(!modalVisible);
        }}
          >
            <View style={styles.centeredView}>
              <View style={styles.modalView}>
                <Pressable
                  style={[styles.button, styles.buttonClose]}
                  onPress={() => closeClue()}
                >
                  <Text style={styles.textStyle}>✕</Text>
                </Pressable>
                <Image style={styles.img} source={modalImage} />
                <Text style={styles.imgText}>{modalImageTxt}</Text>
                <Text style={styles.modalText}>{modalText}</Text>
              </View>
            </View>
          </Modal>
        </View>
      );
    });
  }, [modalVisible, modalUpdate]);
  // returning Modal + Markers
  if (open) {
    return <View>{markermodal}</View>;
  }
  if (!open) {
    return <>{markers}</>;
  }
}

const styles = StyleSheet.create({
  centeredView: {
    flex: 1,
    justifyContent: "flex-start",
    alignItems: "center",
    marginTop: 190,
    marginLeft: 50,
    marginRight: 50,
  },
  modalView: {
    backgroundColor: "black",
    borderRadius: 10,
    padding: 35,
    alignItems: "center",
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  button: {
    borderRadius: 20,
    padding: 8,
    elevation: 2,
  },
  buttonClose: {
    backgroundColor: "white",
  },
  textStyle: {
    color: "black",
    fontWeight: "bold",
    textAlign: "center",
  },
  modalText: {
    marginTop: 15,
    color: "white",
    textAlign: "center",
    fontSize: 20,
  },
  img: {
    width: 100,
    height: 100,
    marginTop: 25,
    borderRadius: 3,
  },
  imgText: {
    color: "white",
    textAlign: "center",
  },
});

And this is the screen with the map in which i use the components and decides what to render with the open prop.

import....

const MapScreen = ({ navigation }) => {
  const [userLocation, setuserLocation] = useState({
    latitude: 59.31858196433116,
    longitude: 18.06945029502431,
    latitudeDelta: 0.02,
    longitudeDelta: 0.02,
  });

  const _onMapReady = useCallback(async () => {
    const { granted } = await Location.requestForegroundPermissionsAsync();
    if (!granted) {
      throw new Error("Location permission not granted");
    }
    const {
      coords: { latitude, longitude },
    } = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.High,
      timeInterval: 500,
      distanceInterval: 10,
    });
    setuserLocation({
      ...userLocation,
      latitude: latitude,
      longitude: longitude,
    });
  }, [userLocation]);

  useEffect(() => {
    _onMapReady();
  }, [_onMapReady]);
  return (
    <SafeAreaProvider style={styles.black}>
      <View style={styles.container}>
        <Timer timer={true} />
        <MapView
          provider={MapView.PROVIDER_GOOGLE}
          style={styles.map}
          initialRegion={userLocation}
          showsIndoors={true}
          zoomControlEnabled={true}
          zoomEnabled={true}
          zoomTapEnabled={true}
          showsBuildings={true}
          toolbarEnabled={false}
          showsUserLocation={true}
          onMapReady={_onMapReady}
          showsMyLocationButton={true}
          customMapStyle={mapStyle}
          loadingEnabled={true}
          followUserLocation={false}
        >
          <MapMarkersClues open={false} trackViewChanges={false} />
        </MapView>
        <MapMarkersClues open={true} styles={viewStyles} />
      </View>
    </SafeAreaProvider>
  );
};

export default MapScreen;

const percent = Dimensions.get("window").height / 100;
const viewStyles = StyleSheet.create({
  container: {
    backgroundColor: "green",
    width: 30,
    height: 5,
    borderColor: "red",
    borderStyle: "solid",
    borderWidth: 3,
    position: "absolute",
    zIndex: 100000,
  },
});

const markerStyles = StyleSheet.create({
  container: {
    border: "2px solid red",
    position: "absolute",
    zIndex: 1,
  },
});
const styles = StyleSheet.create({
  container: {
    position: "relative",
    backgroundColor: "black",
    bottom: 0,
    zIndex: -10,
  },
  map: {
    zIndex: 0,
    width: Dimensions.get("window").width,
    height: percent * 76,
  },
  black: {
    backgroundColor: "black",
  },
});

Ive searched and searched but I cannot understand the problem. Any suggestions?

0 Answers
Related