How to create clickable points of interest in React Native? - reactjs

I want to know how i can create something like this (See the picture) in react native, exactly i mean the clickable points of interest.
Is there any component that solves this problem?
Examples:

You can make a Marker component as shown below. This is just a simple demo, you can modify it as you want
Marker.js
import React from 'react'
import {TouchableOpacity} from 'react-native'
const Marker = ({onPress, top, left}) => (
<TouchableOpacity onPress={onPress} style={{height: 10, width: 10, borderRadius: 5, backgroundColor: 'red', position: 'absolute', top, left}} />
)
export default Marker
Usage
import Marker from './Marker'
_onPress = () => //...Do the stuff here
render() {
return (
<ImageBackground style={{flex: 1}} source={{uri: 'https://s3.envato.com/files/214277896/us-map-html5.png'}} resizeMode={'stretch'}>
<Marker onPress={this._onPress} top={100} left={200} />
</ImageBackground>
)
}

Related

Update Progress bar value when end scrolling in ScrollView on React Native

I have created a functionality , In which show the Progress bar and it's value change according to scrolling the view. the progress bar value should depend that scrolling is end or not if the scrolling is end then the progress bar should completely filled.
I have tired but it's not working. Here my code:
import React, {useState, useEffect} from 'react';
import * as Progress from 'react-native-progress';
import { Card } from 'react-native-paper';
import { Text, View, StyleSheet,ScrollView } from 'react-native';
const scrollView_height = 0;
const scrollViewContent_height = 0;
export default function App() {
const UpdateProgressBar = (progress) => {
setProgress(
Math.abs(
progress.nativeEvent.contentOffset.y /
(scrollViewContent_height - scrollView_height),
),
);
};
return (
<View style={styles.container}>
<Progress.Bar
style={{
position: 'relative',
bottom: 6,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
}}
height={3}
borderWidth={0}
progress={progress_count}
color="red"
width={widthToDp('82%')}
/>
<ScrollView
showsVerticalScrollIndicator={false}
bounces={false}
contentContainerStyle={{paddingBottom: 0}}
onContentSizeChange={(width, height) => {
scrollViewContent_height = height;
}}
onScroll={UpdateProgressBar}
onLayout={(event) =>
(scrollView_height = event.nativeEvent.layout.height)
}
scrollEventThrottle={12}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Card>
<AssetExample />
</Card>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
}
});
Please Suggest the Solution.
import React, {useState, useEffect} from 'react';
import * as Progress from 'react-native-progress';
import { Card } from 'react-native-paper';
import { Text, View, StyleSheet,ScrollView } from 'react-native';
export default function App() {
const [scrollView_height, setScrollView_height] = useState(0)
const [scrollViewContent_height, setScrollViewContent_height] = useState(0)
const [progress, setProgress] = useState(0)
const UpdateProgressBar = (value) => {
setProgress(
Math.abs(
value.nativeEvent.contentOffset.y /
(scrollViewContent_height - scrollView_height),
),
);
};
return (
<View style={styles.container}>
<Progress.Bar
style={{
position: 'relative',
bottom: 6,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
}}
height={3}
borderWidth={0}
progress={progress}
color="red"
width={widthToDp('82%')}
/>
<ScrollView
showsVerticalScrollIndicator={false}
bounces={false}
contentContainerStyle={{paddingBottom: 0}}
onContentSizeChange={(width, height) => {
setScrollView_height(height);
}}
onScroll={UpdateProgressBar}
onLayout={(event) =>
setScrollView_height(event.nativeEvent.layout.height)
}
scrollEventThrottle={12}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a
shareable url.
</Text>
<Card>
<AssetExample />
</Card>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
}
});

BottomTabNavigator coming on top instead of bottom in React Native expo mobile app

I am developing a mobile react native expo app. I am using BottomTabNavigator (NavigationContainer). As the name suggests it should appear at the bottom but it is incorrectly appearing on top.
I already have another image (logo.png) on the top of the screen and the navigationbar (or NavigationContainer) is also coming on top and overlapping above the image. Please help me resolve this issue. See my code below:
In the below code MyTabs is the Navigator created from createBottomTabNavigator(). This is incorrectly appearing on top of the screen.
import React from 'react';
import { Image, StyleSheet, Text, View, SafeAreaView, StatusBar, Platform } from 'react-native';
import logo from './assets/logo.png';
import { NavigationContainer } from '#react-navigation/native';
import MyTabs from './navigator/AppNavigator';
export default function App() {
return (
<SafeAreaView style={{ paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight: 0 }} >
<View>
<View style={styles.container}>
<Image source={logo} style={{ width: 100, height: 100 }} />
<Text style={{color: '#888', fontSize: 18, alignItems: 'center'}}>
To share a photo from your phone with a friend or anyone, just press the button below!
</Text>
</View>
<View >
<NavigationContainer >
<MyTabs /> // This is incorrectly coming on top of screen.
</NavigationContainer>
</View>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
// justifyContent: 'center',
},
});
The NavigationContainer should be the outermost component in App. This then wraps the Tab.Navigator component (in your case MyTabs), where you create tabs linked to each of your components. Inside your components, you are able to utilize SafeAreaView to then display the image at the top of the screen. Any type of Navigation scheme has to be made the top most component in the hierarchy in react native, wrapping the rest of your components. I've altered your code below:
import React from 'react';
import { Image,  StyleSheet, Text, View, SafeAreaView, StatusBar, Platform } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
export default function App() {
  const Tab = createBottomTabNavigator()
  return (
    <NavigationContainer >
      <Tab.Navigator>  
        <Tab.Screen name="Home" component={myComponent} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
const myComponent = () => {
  return (
    <SafeAreaView style={{ paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight: 0 }} >
      <View>
        <View style={styles.container}>
          <Image source={require('#expo/snack-static/react-native-logo.png')} style={{ width: 100, height: 100 }} />
          <Text style={{color: '#888', fontSize: 18, alignItems: 'center'}}>To share a photo from your phone with a friend or anyone, just press the button below!</Text>
        </View>
      </View>
    </SafeAreaView>
  )
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
     alignItems: 'center',
    // justifyContent: 'center',
  },
});

Show loading indicator between navigation of pages in a Webview

I have a url in the Webview like https://www.nytimes.com/ The current code works inital page load but If I type tap anything in the link, the page takes a while to load and there are no loading indicators in the website. Is there any way we can put a page loading indicator in React Native while we click on any link or page loading specially if it is server side rendered like next js?
Here is my ReactNative code.
import * as React from 'react';
import {
View,
Text,
Image,
SafeAreaView,
ScrollView,
TextInput,
TouchableOpacity,
} from 'react-native';
import styles from './styles';
import { WebView } from 'react-native-webview';
// import WelcomeSwiper from '../../components/WelcomeScreen/WelcomeSwiper';
import LoadingIcon from '../../components/Loading/index.js';
const WebView = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<WebView
javaScriptEnabled={true}
domStorageEnabled={true}
renderLoading={LoadingIcon}
source={{ uri: 'https://www.nytimes.com/ ' }}
startInLoadingState={true}
/>
</SafeAreaView>
);
};
export default WebView;
Here is my loading component
import React from 'react';
import { StyleSheet, Platform, ActivityIndicator } from 'react-native';
const LoadingIcon = () => {
return (
<ActivityIndicator
color='#009688'
size='large'
style={styles.ActivityIndicatorStyle}
/>
);
}
export default LoadingIcon;
const styles = StyleSheet.create(
{
WebViewStyle:
{
justifyContent: 'center',
alignItems: 'center',
flex: 1,
marginTop: (Platform.OS) === 'ios' ? 20 : 0
},
ActivityIndicatorStyle: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
}
});
we can use these two approaches to get the result:
You can check if the WebView is loading something or not with the onLoadProgress method. This method gives you a number between 0 and 1. If the page is fully loaded it will return number 1, update your state and show the ActivityIndicator according to it:
you can use onLoadStart and onLoadEnd to update your state and show the ActivityIndicator according to it!
for more info check the: https://github.com/react-native-community/react-native-webview/blob/master/docs/Reference.md#onloadprogress
you can also use your ActivityIndicator wrapped by WebView, *do not Forget this method works in ios for android put it outside of WebView
and this is a working code sample for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadStart={(syntheticEvent) => {
setLoading(true);
}}
onLoadEnd={(syntheticEvent) => {
setLoading(false);
}} />
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;
I hope it helps
I use onLoadProgress to solve this issue.
renderLoading function is just called at the initial loading state of webview component. Using renderLoading is not helpful to show activity indicators at any tap on page links or navigating between webview pages.
Checking onLoadStart and onLoadEnd is useful in android but in iOS onLoadEnd is not called in the back navigation gesture which results in endless spinning of activity indicator.
onLoadProgress returns a number between 0-1 while webview is in the loading state. You check its progress state and update your activity indicator state.
For more information about onLoadProgress: onLoadProgress
Here is a working code example for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadProgress={({nativeEvent}) => {
if (nativeEvent.progress != 1 && isLoading == false ) {
setLoading(true)
} else if (nativeEvent.progress == 1 ) {
setLoading(false)
}
}}
/>
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;

Is there a way to have a button render my camera component in React Native?

I am new to react native and am trying to make my camera component pop up whenever I click on a button. I am able to get the camera to render in App.js, but the minute I try to get it rendering in the component it just doesn't work. Should I use state to get this to render? If so, why doesn't react native allow you to just render a component within a component? I'm trying to understand the concept of components calling other components. Heres my code:
import React, {Component} from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';
import DeviceCamera from './camera';
class CameraButton extends Component {
render() {
return (
<View style={styles.container}>
<Text> Button to Open Camera </Text>
<Button
onPress={() => {
<DeviceCamera />;
}}
title="click me to open the camera!"
color="#841584"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
export default CameraButton;
I was trying to use the on press function to call the camera component but perhaps I am misunderstanding something.
Yeah, I would probably just use state here
class CameraButton extends Component {
showCamera = () => this.setState({ showCamera: true });
render() {
return (
<View style={styles.container}>
<Text> Button to Open Camera </Text>
<Button
onPress={this.showCamera}
title="click me to open the camera!"
color="#841584"
/>
{this.state.showCamera && <DeviceCamera />}
</View>
);
}
}
With JSX, you can use foo && <Bar />; if foo evaluates to something truthy, then it will render your component, otherwise it will not.

Simple React Native Image Game is Lagging.How do i optimize?

I am trying to implement a simple img tapping game with react native for learning purposes.I am using this librarys https://github.com/bberak/react-native-game-engine game loop component as a game loop.
What I am trying to do is render some imgs with random locations on screen with small radius then increase it up to a value, after decrease it and finally remove the img from screen (or when tapped) - just like in this game: http://mouseaccuracy.com/
import React, { Component } from "react";
import { AppRegistry, StyleSheet, Dimensions, View,ToastAndroid,TouchableOpacity,Image,Text } from "react-native";
const { width: WIDTH, height: HEIGHT } = Dimensions.get("window");
import { GameLoop } from "react-native-game-engine";
import { Fonts } from '../utils/Fonts';
import FastImage from 'react-native-fast-image'
import * as Progress from 'react-native-progress';
import SwordImage from "../assets/tapfight/sword.png";
import ShieldImage from "../assets/tapfight/shield.png";
this.renderSwordOrCircle(circle)
)
})
)
}
}
renderHealth = () =>{
return(
<View>
<View style={{ alignItems:'center' ,position: "absolute", top: 0, left: 0}}>
<Text style={{fontFamily:Fonts.MainFont,color:'white',fontSize:25}}>{this.playerHealth}</Text>
<Progress.Bar color='red' progress={this.playerHealth/100} width={100} height={18} />
</View>
<View style={{ alignItems:'center',position: "absolute", top: 0, right: 0}}>
<Text style={{fontFamily:Fonts.MainFont,color:'white',fontSize:25}}>{this.enemyHealth}</Text>
<Progress.Bar color='red' progress={this.enemyHealth/100} width={100} height={18} />
<FastImage resizeMode="contain" style={{width:100,height:100}} source={require('../assets/tapfight/guard_2_head.png')}></FastImage>
</View>
</View>
)
}
render() {
if(this.state.fight==true){
return (
<View style={{flex:1,backgroundColor:'transparent'}} >
<GameLoop style={{flex:1}} onUpdate={this.updateCircle}>
{this.renderHealth()}
{this.renderCircles()}
</GameLoop>
</View>
);
}else{
return(
null
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
}
});
What i am doing is i am generating images every 600 ms on screen and player tries to tap them.The problem is when there is more than 2 images on screen fps drops significantly.Tested in android actual device.I am updating state once at the end of updateCircle function.
Game loop is updateCircle component
Your problem is that you're trying to animate a component that is not made for being animated.
I dont know well the FastImage component, but I understand that it purpose is to pre-load images, not animate.
You shoud use Animated.Image for the image, and Animated.timing for managing the animations of Animated.Image

Resources