React Native Maps Custom Marker blocking Marker onPress - reactjs

I have custom markers being rendered to my map and do so exactly as I want. I'm using Custom Marker which is a View, Image, and then text specific to an event over the image.
For some reason using a custom marker view is blocking the onPress on the Marker component.
I've tested the onPress event as similiar to below for testing:
<Marker onPress={() => {console.log('Pressed')}}> ... but only logs the press message when I remove my custom marker view inside the Marker component.
Is there a reason why the custom marker view would be stopping the onPress? How do I get around this and fire an onPress event for a custom marker?
Added full code below for better look. Right now it is working but only because I am using the onSelect event for iOS. The onPress works the way it is for Android but not iOS.
<MapView
style={styles.map}
ref={ map => {this.map = map }}
region={this.state.region}
onRegionChangeComplete={this.onRegionChange}
rotateEnabled={false}
loadingEnabled={true}
>
{matches.map((marker, index) => {
return (
<MapMarker
key={index}
mapMarker={marker}
handlePress={() => {
this.map.animateToRegion({
latitude: marker.location.latlng.latitude,
longitude: marker.location.latlng.longitude
}, 100)
}}
/>
)
})}
</MapView>
MapMarker.js
render() {
const { mapMarker } = this.props;
return (
<Marker
ref={(ref) => {this.markerRef = ref; }}
coordinate={mapMarker.location.latlng}
title={mapMarker.location.streetName}
stopPropagation={true}
pointerEvents='auto'
onPress={() => console.log('pressed')}
onSelect={() => {
this.props.handlePress();
}}
>
<CustomMapMarker
gameType={mapMarker.matchType}
isSanctioned={mapMarker.isSanctioned}
startDate={mapMarker.startAt}
/>
<Callout style={styles.customCallout}>
<CustomMarkerCallout markerInfo={mapMarker} />
</Callout>
</Marker>
);
}

Fixed the issue by adding onSelect which is iOS specific. The onPress was only working for Android so don't know if this is the right answer but is working for me as of now.

Related

Why my modal does not show up in react native iOS. But its working in react native android

I am in the strange situation. I always develop my app using android simulator. Since running two simulators both iOS and android always turn my pc into oven.
I am using redux in this app.
I got a component called cart. Whenever user tried to access this component I am testing if the user got item added to the cart or not. I am using useEffect hook to test it.
My cart component look like this
//Fetch cart data
let cartList = useSelector((state) => state.productReducer.cartList);
useEffect(() => {
if (cartList?.OrderDTO?.Id === null) {
setModalVisible(true);
//alert("your Cart is empty")
}
}, []);
useEffect(() => {
if (cartList?.OrderDTO?.Id === null) {
setModalVisible(true);
//alert("your Cart is empty")
}
}, [cartList]);
return (
<ScrollView style={styles.pageContainer}>
<Loader loading={loading} />
<View>
<NotiDialog
modalVisible={modalVisible}
setVisible={setModalVisible}
contentText="Your cart is empty"
comfirmText="OK"
comfirm={() => handleEmptyCart()}
titleText="Notification"
/>
<ComfirmDialog
modalVisible={modalTwoVisible}
setVisible={setModalTwoVisible}
contentText="Are you sure you want to empty the cart? "
comfirmText="OK"
comfirm={() => emptyTheCart()}
titleText="Notification"
/>
</View>
I already fetch cartData once when the app is loaded
As you can see in the useEffect I am using setModalVisible(true) to show up the modal.
But the problem is that this modal popup in android always. I already tried about 100 times. But in iOS its never show up
So instead of modal I tried to open up the ***commented*** alert in iOS. The message your Cart is empty popup. But the modal doesn't. So is there something wrong with my modal?
Here is my modal component
import {
...,
Modal,
} from 'react-native';
const NotiDialog = ({
modalVisible,
setVisible,
comfirm,
comfirmText,
contentText,
titleText,
}) => {
const confirmFunc = () => {
comfirm();
setVisible(false);
};
return (
<View style={styles.centeredView}>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<View style={styles.centeredView}>
...
</View>
</Modal>
</View>
);
};
try setTimeout() before opening the modal

React leaflet How to have all markers with a specific icons but the one active with a different icon

So I am trying to have an active marker that is different from the rest of the non active marker.
So basically I want something like this.
To display all of the icon I am using the following.
that is displayed inside the map
{parkdata.features.map(park =>(
<Marker key = {park.properties.PARK_ID} position={[
park.geometry.coordinates[1],
park.geometry.coordinates[0]
]}
onClick={()=>{this.selected(park);
The selected function that was intended to be used to change the active icon. But it does not seem to be doing anything
selected(park){
return(
<Marker key = {park.properties.PARK_ID} position={[
park.geometry.coordinates[1],
park.geometry.coordinates[0]
]}
icon= {active}
/>
)
}
UPDATE:
This is what I have now.
SO when I click on one of the markers I want to change to a different icon. For now, it just does not do anything.
The following example demonstrates how to create a markers and update icon property on marker click:
function createIcon(url) {
return new L.Icon({
iconUrl: url,
});
}
function MapExample(props) {
const [selectedIndex, setSelectedIndex] = useState(-1);
function handleClick(e) {
setSelectedIndex(e.target.options.index) //get index via custom marker property
}
function getMarkerIcon(index) {
if(index === selectedIndex)
return createIcon("/bigcity_red.png");
return createIcon("/bigcity_green.png");
}
return (
<Map center={props.center} zoom={props.zoom}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
{props.data.map((item, index) => (
<Marker
key={index}
index={index}
position={item.position}
icon={getMarkerIcon(index)}
onclick={handleClick}
/>
))}
</Map>
);
}
Notes:
icon property for Marker component expects the value of L.Icon type
selectedIndex state is used to keep track of selected Marker (index)
Here is a demo for your reference

Cannot use the function hideCallout from react native maps

I am currently trying to close my callout when I press the X button of a card on my app.
My code is this. ** function of closing card **
unsetCard = id => {
this.setState({
...this.state,
showCard: false,
});
this.markers.hideCallout();
if (this.state.keyboard) {
Keyboard.dismiss();
}
};
And this is my ** Map View code, I use RN Clustering **
<MapView
//
mapRef={ref => (this.myMapRef = ref)}
//
onPress={this.unsetCard}>
{this.props.data.map(marker => (
<Marker
key={marker.id}
ref={ref => (this.markers = ref)}
//
}>
<Callout
//
}}>
<CustomCallout title={marker.t} />
</Callout>
</Marker>
))}
</MapView>
Finally the function of unset card is called in this component in the same file:
<CustomCardWithImage
close={() => this.unsetCard(this.state.cardInfo.id)}
/>
I would appreciate if someone told me how to use the ref to the marker, because as much as I try it does not work.
Thanks in advance,
After seriously considering not continuing with this app, I took a break and solved the problem. Here is how you can use show or hide callout if you are interested:
Initialize markers
constructor(props) {
super();
this.markers = [];
}
Create markers refs
<Marker
key={marker.id}
ref={ref => {
this.markers[marker.id] = ref;
}}>
Call where needed
this.markers[id].hideCallout();
I hope someone finds it helpful someday

Question about custom header in React Navigation v5 (Not clickable back button)

Hi I am using React navigation v5.
I am trying to implement custom header for specific screen. So my custom header looks like this
CustomHeader.js
export function CustomHeader({props}) {
const {scene, previous, navigation} = props;
const opacity = scene.route.params.opacity;
return (
<React.Fragment>
<Animated.View style={[styles.headerStyle, {opacity}]}>
<View style={styles.influencerNameContainer}>
<Text style={styles.influencerName}>
{scene.route.params.influencer.user.name}
</Text>
</View>
</Animated.View>
{previous ? (
/* This is a back button */
<Button
style={[styles.iconButton, {left: 0}]}
icon={BackIcon}
onPress={() => {navigation.goBack}
/>
) : (
undefined
)}
</React.Fragment>
);
}
Navigator looks like this
export function HomeStack() {
return (
<Stack.Navigator
initialRouteName="Home"
headerMode="screen"
style={{backgroundColor: 'yellow'}}>
<Stack.Screen
name="InfluencerScreen"
component={InfluencerScreen}
options={{
header: props => <CustomHeader props={props} />,
}}
/>
</Stack.Navigator>
);
}
It renders custom headers and custom back button but back button is not clickable.
So I tried.
<Stack.Screen
name="InfluencerScreen"
component={InfluencerScreen}
options={{
header: props => <CustomHeader props={props} />,
headerLeft: () => (
<Button title="Back Button" onPress={() => alert('Pressed')} />
)
}}
/>
With this code, it doesn't show back button at all with custom header. But it shows custom back button when I remove custom header(header: props => ).
What am I missing?
You're showing a custom header, how you render the button is up-to you. React Navigation cannot show a back button since React Navigation is no longer rendering the header.
Instead of using headerLeft option, you need to put the back button inside your custom header.
Also your destructuring is incorrect. function CustomHeader({props}) should be function CustomHeader(props) (without the curly braces).
You're destructuring props twice.. Try:
export function CustomHeader({scene, previous, navigation}) {
// const {scene, previous, navigation} = props; // remove this
...
}
Edit:
Also goBack is a method so call it with parentheses:
onPress={() => navigation.goBack()} // remove unnecessary `curly braces`

Webview not working in react-native-element Overlay

I'm using react-native-element for ready-made components in my application and using Overlay to show modals through out the application.
Now the issue is I've a Modal in which I want to show Webview but it doesn't showup on the screen.
My modal code looks like this
export const Modal = ({ visible, showCrossBtn, setModalVisible, backgroundColor, children }) => {
return (
<Overlay
isVisible={visible}
fullScreen={false}
height="auto"
overlayBackgroundColor={backgroundColor}
overlayStyle={styles.overlay}
onBackdropPress={() => setModalVisible(false)}>
<View style={styles.dialogBox}>
{
showCrossBtn && <TouchableOpacity style={[styles.crossPosition, styles.crossStyling]} onPress={() => setModalVisible(false)}>
<Icon name="cross" type="entypo" color={colors.gray} size={30} />
</TouchableOpacity>
}
<View style={styles.body}>
{children}
</View>
</View>
</Overlay>
)
}
In my basic component
export const Home = ({ }) => {
return (
....
....
<Modal
visible={this.props.visible}
setModalVisible={this.props.setModalVisible}
backgroundColor={colors.lightgray}
showCrossBtn={false}
>
<WebView
style={[{ height: 20 }, styles.webView]}
originWhitelist={['*']}
ref={e => webview = e}
source={{ html: '<p>HELLO WORLD</p>'}} />
</Modal>
)
}
Using WebView in modals can be tricky due to the height and width.
To solve the issue, I've created a Snack using react-native-elements Overlay component and WebView. I used some of your code and remove any redundant code for brevity.
Use iOS or Android simulator to run the snack. You can also use your physical device to run the snack using expo app.
Snack - https://snack.expo.io/r1H4FSHML

Resources