How to scroll To next item on a button click using FlatList in React Native? - react-native

I have an array of months which I am using to display months using a horizontal FlatList. I want the months to change using 2 buttons that are forward button to change the month in increasing order i.e from January to February and so on and a back button to change the month backwards i.e from January to December.
How can I make the buttons do so. Below monthName is an array that contains all the month names.
<ScrollView style={{flexGrow: 1}}>
<View style={{flex: 1, backgroundColor: '#fff', height: hp('130')}}>
<View
style={{
justifyContent: 'space-evenly',
width: wp('48'),
}}>
<FlatList
data={monthName}
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
renderItem={(month, index) => (
<View>
<Months
showMonth={month.item}
id={month.id}
refer={flatRef}
/>
</View>
)}
keyExtractor={(item, index) => item.id.toString()}
horizontal
// snapToInterval={Dimensions.get('window').width}
snapToAlignment={'center'}
ref={(node) => (flatRef = node)}
/>
</View>
<View
style={{
justifyContent: 'space-evenly',
width: wp('12'),
}}>
{/* {} */}
<IonIcons.Button --> the button that makes the month increment.
name="arrow-forward"
size={25}
backgroundColor="white"
color="black"
// onPress={() => console.log('pressed')}
onPress={() => {
flatRef.scrollToIndex({index: ?});
}}
/>
</View>
</View>
</ScrollView>

try to access ref using current and it should work
this.flatRef.current.scrollToIndex({index: monthName.length > this.state.currentindex ? this.state.currentindex++ : this.state.currentindex });

import React, { useRef } from 'react';
import {
FlatList,
StyleSheet,
Text,
TouchableOpacity,
View
} from 'react-native';
import { wp } from '../../constants/scaling';
import { colors } from '../../constants/theme';
import bookingprocess from '../../data/BookingProcess';
import { textStyles } from '../../styles/textStyles';
import { RFValue } from 'react-native-responsive-fontsize';
import AntDesign from 'react-native-vector-icons/AntDesign';
const BookingProcess = ({}) => {
const flatListRef = useRef(FlatList);
const nextPress = index => {
if (index <= 2) {
flatListRef?.current?.scrollToIndex({
animated: true,
index: index + 1
});
}
};
const backPress = index => {
if (index >= 1) {
flatListRef?.current?.scrollToIndex({
animated: true,
index: index - 1
});
}
};
return (
<View
style={{
...styles.cardView,
padding: 0,
elevation: 0,
borderWidth: 1,
borderColor: '#f2f2f2',
overflow: 'hidden'
}}>
<View
style={{
padding: wp(2),
backgroundColor: colors.primaryColor
}}>
<Text
style={{
...textStyles.heading,
color: '#fff'
}}>
Booking Process
</Text>
</View>
<Text
style={{
...textStyles.mediumheading,
padding: wp(2),
paddingBottom: 0
}}>
You can reserve your parking slot in advance. Please follow
these four simple steps to book your parking slot.
</Text>
<FlatList
data={bookingprocess}
horizontal={true}
ref={flatListRef}
contentContainerStyle={{ padding: wp(2) }}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => item.id}
renderItem={({ item, index }) => {
return (
<View style={styles.innerCard}>
{item.image}
<View style={styles.ButtonBox}>
<TouchableOpacity
onPress={() => backPress(index)}
style={{
backgroundColor: colors.secondaryColor,
borderRadius: wp(50)
}}>
<AntDesign
name="leftcircle"
size={RFValue(25)}
color={colors.primaryColor}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={() => nextPress(index)}
style={{
backgroundColor: colors.secondaryColor,
borderRadius: wp(50)
}}>
<AntDesign
name="rightcircle"
size={RFValue(25)}
color={colors.primaryColor}
/>
</TouchableOpacity>
</View>
<View style={styles.innercardHeaderView}>
<Text style={styles.headingTextNumber}>
{item.id}. {item.title}
</Text>
</View>
<Text style={styles.description}>
{item.description}
</Text>
</View>
);
}}
/>
</View>
);
};
export default BookingProcess;
const styles = StyleSheet.create({
cardView: {
backgroundColor: colors.white,
margin: wp(2),
elevation: 4,
borderRadius: wp(2),
padding: wp(2),
width: wp(94)
},
innerCard: {
margin: wp(2),
borderRadius: wp(2),
padding: wp(0),
paddingTop: 0,
paddingHorizontal: 0,
overflow: 'hidden',
width: wp(90),
elevation: 5,
marginLeft: 0,
padding: wp(2),
backgroundColor: '#fff'
},
ButtonBox: {
position: 'absolute',
flexDirection: 'row',
right: 0,
justifyContent: 'space-between',
width: wp(20),
padding: wp(2)
},
innercardHeaderView: {
backgroundColor: '#0000',
flexDirection: 'row',
padding: wp(2),
paddingBottom: 0,
alignItems: 'center'
},
headingTextNumber: {
...textStyles.heading,
color: colors.primaryColor,
textAlign: 'center',
alignSelf: 'center',
textAlignVertical: 'center'
},
description: {
...textStyles.mediumheading,
paddingHorizontal: wp(2),
textAlign: 'justify'
}
});

Instead of using a FlatList I would suggest you to make a state variable and execute it like this
Working example - Here
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { AntDesign } from '#expo/vector-icons';
...
const [SelectMonth, SetSelectMonth] = React.useState(monthName[0]);
const NextPress = () => {
if (SelectMonth.id !== 12) {
let temp = monthName.find((c) => c.id === SelectMonth.id + 1);
if (temp) {
SetSelectMonth(temp);
}
}
};
const PrevPress = () => {
if (SelectMonth.id !== 1) {
let temp = monthName.find((c) => c.id === SelectMonth.id - 1);
if (temp) {
SetSelectMonth(temp);
}
}
};
return (
<View style={styles.container}>
<View style={styles.CalenderBox}>
<AntDesign
name="caretleft"
size={30}
color="black"
onPress={() => PrevPress()}
/>
<View style={styles.MonthNameBox}>
<Text style={{ fontWeight: 'bold', fontSize: 24 }}>
{SelectMonth.name}
</Text>
</View>
<AntDesign
name="caretright"
size={30}
color="black"
onPress={() => NextPress()}
/>
</View>
</View>
);

Related

FlatList - react native not scrolling

I am unable to get my Flatlist to scroll in my expo react native app. At the moment it is just static, displaying a grid of images int he Flatlist with no scrolling functionality. Please can someone advise?
I am unable to get my Flatlist to scroll in my expo react native app. At the moment it is just static, displaying a grid of images int he Flatlist with no scrolling functionality. Please can someone advise?
import { StyleSheet, Text, View, Button, TextInput, TouchableWithoutFeedback, Keyboard, FlatList, ActivityIndicator } from 'react-native';
import { Image } from '#rneui/themed';
import ImageAPI from '../shared-components/ImageAPI';
export default function Home({ navigation }) {
const onCreate = () => {
console.log('create my image now');
};
return (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={styles.container}>
{/** Enter text prompt */}
<View style={styles.section1}>
<View style={styles.txtInputView}>
<TextInput
style={styles.txtInput}
placeholder='Enter a prompt - a description of what you want to create'
multiline={true}
numberOfLines={4}
/>
</View>
<View style={styles.buttonView}>
<Text
style={styles.createBtnText}
onPress={onCreate}
>Create</Text>
</View>
</View>
{/** PROMPT EXAMPLES */}
<View style={styles.section2}>
<View style={styles.section2_sub0}>
<Text style={styles.promptEgTxt}>Prompt Examples</Text>
</View>
<View style={styles.section2_sub1}>
<ImageAPI />
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
section1: {
flex: 2,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ffc6e2',
},
section2: {
flex: 5,
width: '100%',
backgroundColor: '#F8DB93',
},
// section3: {
// flex: 3,
// backgroundColor: '#BCF893',
// },
txtInputView: {
flex: 3,
width: '85%',
height: '50%',
alignItems: 'center',
justifyContent: 'center',
marginTop: 20,
marginBottom: 20
},
buttonView: {
flex: 2,
width: '70%',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 20,
backgroundColor: '#EE4A4A',
borderRadius: 40
},
txtInput: {
borderColor: '#AAAAAA',
borderWidth: 2,
padding: 10,
borderRadius: 15,
// width: '85%',
// height: '50%',
width: '100%',
height: '100%',
fontSize: 15,
},
createBtnText: {
fontSize: 18,
fontWeight: 'bold',
// backgroundColor: '#EEEC4A'
},
section2_sub0: {
flex: 1,
width: '100%',
height: '100%',
backgroundColor: '#EEEC4A',
justifyContent: 'center',
},
promptEgTxt: {
fontSize: 15,
fontWeight: 'bold',
marginLeft: 10
},
section2_sub1: {
flex: 8,
width: '100%',
height: '100%',
backgroundColor: '#A9F889'
},
});
This is the ImageAPI.js file:
import React from 'react';
import { FlatList, SafeAreaView, StyleSheet, ActivityIndicator, View, ScrollView } from 'react-native';
import { Image } from '#rneui/themed';
const BASE_URI = 'https://source.unsplash.com/random?sig=';
const ImageAPI = () => {
return (
<>
<SafeAreaView>
<FlatList
data={[...new Array(10)].map((_, i) => i.toString())}
style={styles.list}
numColumns={2}
keyExtractor={(e) => e}
renderItem={({ item }) => (
<Image
transition={true}
source={{ uri: BASE_URI + item }}
containerStyle={styles.item}
PlaceholderContent={<ActivityIndicator />}
/>
)}
/>
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({
list: {
width: '100%',
backgroundColor: '#000',
},
item: {
aspectRatio: 1,
width: '100%',
flex: 1,
},
});
export default ImageAPI
you need to give it a fixed height and set the contentContainerStyle prop to { flexGrow: 1 }. This will allow the content inside the FlatList to exceed the bounds of the container and be scrollable.
<View style={styles.section2_sub1}>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
data={data}
renderItem={({ item }) => <ImageAPI data={item} />}
keyExtractor={(item) => item.id}
/>
</View>
Try adding flex according to your requirement to your <SafeAreaView> which is the parent to your <Flatlist> Something like this:
<>
<SafeAreaView style = {{flex: 8}} >
<FlatList
data={[...new Array(10)].map((_, i) => i.toString())}
style={styles.list}
numColumns={2}
keyExtractor={(e) => e}
renderItem={({ item }) => (
<Image
transition={true}
source={{ uri: BASE_URI + item }}
containerStyle={styles.item}
PlaceholderContent={<ActivityIndicator />}
/>
)}
/>
</SafeAreaView>
</>
Or remove the SafeAreaView if not required.
Both should work.

How to make TouchableOpacity image look like pressed in?

I have an image in each TouchableOpacity and I would like to change the picture in every onPress function so she could looked like shes pressed in (for example: remove the color from to picture and changes it to black and white or make a light gray shadow on the picture ).
and Reverse (when you click shes changing back to the original picture (Press:true/false).
I have a stateless Component and no class.
My Component :
export default function Recipie({ navigation, route }) {
const recipies = GetRecipies();
return (
<View style={{ flexGrow: 1, flex: 1 }}>
<ScrollView>
{recipies.map((u, i) => {
return (
<View key={i}>
<Text
onPress={navigation.navigate}
style={{
fontSize: 25,
fontFamily: "Cochin",
textAlign: "center",
}}
>
{u._recipieName}
</Text>
<TouchableOpacity
onPress={() => {
navigation.navigate("SingleRecipieScreen", { u });
}}
>
<Image
style={{
height: 200,
width: 350,
borderRadius: 80,
alignSelf: "center",
}}
source={{ uri: u._imgUrl }}
/>
</TouchableOpacity>
<Text
style={{
fontSize: 17,
fontFamily: "Cochin",
textAlign: "center",
}}
>
{u._recipieDescription}
</Text>
<TouchableOpacity
style={{ flex: 1, flexDirection: "column", flexGrow: 1 }}
>
{Show(u._preparationTime)}
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
);
}
Try to use position absolute in View to cover button , and useState for styles, example :
import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View,Image } from "react-native";
const App = () => {
const [isPressed, setIsPressed] = useState(0);
const onPress = () => setIsPressed(!isPressed);
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={onPress}
>
<View style={isPressed && styles.pressedButtonStyle} />
<Text> {isPressed ? "Pressed" : " Press Here"}</Text>
<Image
style={ styles.tinyLogo}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
paddingHorizontal: 10,
},
button: {
alignItems: "center",
backgroundColor: "#DDDDDD",
},
tinyLogo: {
width: 50,
height: 50,
},
pressedButtonStyle: {
position:"absolute",
width:"100%",
height:"100%",
backgroundColor:'black',
opacity:0.6,
zIndex:100,
}
});
https://snack.expo.dev/ixeOwAg3o

i have a problem with passing params to a route in react native navigation. `route.params` is undefined sorry am abit new to react native

Here is my homepage. and i was to navigate to the bookings page while passing a uuid as a param to the bookings page.
import React from "react";
import {
Text,
View,
StatusBar,
ActivityIndicator,
StyleSheet,
SafeAreaView,
TextInput,
TouchableOpacity,
} from "react-native";
import { useFocusEffect } from "#react-navigation/native";
import APIKit from "../config/api/APIKit";
import Icon from "react-native-vector-icons/Feather";
import Card from "../components/Card";
import { ScrollView } from "react-native-gesture-handler";
function HomeScreen({ navigation }) {
const [loading, setLoading] = React.useState(true);
const [items, setItems] = React.useState([]);
const [limit, setLimit] = React.useState(7);
const image = require("../assets/pic1.jpg");
useFocusEffect(
React.useCallback(() => {
getData();
return () => {
setItems([]);
setLimit(9);
};
}, [])
);
const getData = () => {
setLoading(true);
APIKit.get(`items/?limit=${limit}&offset=1`)
.then((res) => {
console.log(res.data);
setLimit(limit + 6);
setItems([items, ...res.data.results]);
setLoading(false);
})
.catch((e) => console.log(e.request.response));
};
return (
<SafeAreaView
style={{ alignItems: "flex-start", justifyContent: "center" }}
>
<StatusBar style="auto" />
<View style={{ padding: 8 }}>
<View
style={{
flexDirection: "row",
alignItems: "center",
width: "100%",
marginTop: 5,
}}
>
<TextInput
placeholder={"Enter Item Name"}
style={{
flex: 1,
backgroundColor: "white",
height: 40,
borderColor: "black",
borderWidth: 1,
borderRadius: 5,
margin: 2,
paddingLeft: 8,
}}
/>
<TouchableOpacity
style={{
alignItems: "center",
alignSelf: "center",
borderWidth: 1,
width: 50,
borderRadius: 500,
}}
>
<Icon name="search" size={25} />
</TouchableOpacity>
</View>
<View style={{ flex: 1, marginTop: 20 }}>
<ScrollView>
<View
style={{
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "flex-start",
}}
>
{items !== []
? items.map((item, key) => {
return (
<Card
key={key}
name={item.item_name}
description={item.description}
onHandlePress={() =>
navigation.navigate("payment-options", {
uuid: item.uuid,
price: item.cost,
})
}
image={image}
/>
);
})
: null}
</View>
<TouchableOpacity
activeOpacity={0.9}
onPress={getData}
//On Click of button load more data
style={styles.loadMoreBtn}
>
<Text style={styles.btnText}>Load More</Text>
{loading ? (
<ActivityIndicator color="white" style={{ marginLeft: 8 }} />
) : null}
</TouchableOpacity>
</ScrollView>
</View>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
footer: {
padding: 10,
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
},
loadMoreBtn: {
padding: 10,
width: 350,
marginHorizontal: 20,
alignSelf: "center",
backgroundColor: "#01ab9d",
borderRadius: 4,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
},
btnText: {
color: "white",
fontSize: 15,
textAlign: "center",
},
});
export default HomeScreen;
and the booking page looks like this
import { Text, View, StatusBar, SafeAreaView, StyleSheet } from "react-native";
import { Button } from "react-native-elements";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
function PaymentOptionScreen(props) {
return (
<SafeAreaView
style={{ flex: 1, alignItems: "center", justifyContent: "center" }}
>
<StatusBar style="auto" />
<View style={{ flex: 1, justifyContent: "flex-start", margin: 20 }}>
<Button
title="Pay Now"
onPress={() =>
console.log(props.route.params)
}
containerStyle={styles.ButtonContainer}
buttonStyle={{ height: 60, justifyContent: "flex-start" }}
icon={<Icon name="cash" size={40} color="white" />}
/>
<Button
title="Pay on delivery"
containerStyle={styles.ButtonContainer}
buttonStyle={{ height: 60, justifyContent: "flex-start" }}
icon={<Icon name="cash" size={40} color="white" />}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
ButtonContainer: {
width: 380,
},
});
export default PaymentOptionScreen;
here is a snippet of the of the app.js it may help
<AuthContext.Provider value={authContext}>
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen name="Home" component={HomeStackScreen}/>
<Drawer.Screen name="Profile" component={ProfileStackScreen}/>
<Drawer.Screen name="Bookings" component={BookingsStackScreen}/>
<Drawer.Screen name="payment-options" component={PaymentOptionsScreenStack}/>
<Drawer.Screen name="Add Item" component={AddItemStackScreen}/>
<Drawer.Screen name="Settings" component={SettingsStackScreen}/>
<Drawer.Screen name="Messages" component={MessagesStackScreen}/>
</Drawer.Navigator>
</NavigationContainer>
</AuthContext.Provider>
Can you print the props? I think you have to pass it as object {props}
If you are using navigation 5.0 . Try this
const App=({navigation, route })=>{
const uuid = route.param;
return (
<View</View>
);
}

calling modal from another component in react native wont open modal

I am trying to open a modal from another component.
this is in my parent component:
const [modalVisible, setModalVisible] = useState(false);
<TouchableOpacity
style={styles.gateBtn}
onPress={() => {
setModalVisible(true);
}}
>
<Text style={styles.gateBtnText}>Show Modal</Text>
<OpenModal isModalVisible={modalVisible} />
</TouchableOpacity>
and this is my OpenModal.js
import React, { useState } from "react";
import {
StyleSheet,
View,
Text,
Alert,
Modal,
TouchableHighlight,
} from "react-native";
function OpenModal(props) {
const [modalVisible, setModalVisible] = useState(false);
return (
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Hello World!</Text>
<TouchableHighlight
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22,
},
modalView: {
margin: 20,
backgroundColor: "white",
borderRadius: 20,
padding: 35,
alignItems: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
openButton: {
backgroundColor: "#F194FF",
borderRadius: 20,
padding: 10,
elevation: 2,
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center",
},
modalText: {
marginBottom: 15,
textAlign: "center",
},
});
export default OpenModal;
however It seems like I am doing something wrong,
I am trying to pass modalVisible to OpenModal by using isModalVisible={modalVisible} and modalVisible is already defined as false, when clicking on the button it becomes true, but in my OpenModal component It seems like its undefined, and it doesnt open the modal at all. What am I missing here?
you need to pass in the setModalVision, then use the props.modalVisible from the parent component.
in parent
<OpenModal isModalVisible={modalVisible} setModalVisible={setModalVisible} />
child component
function OpenModal(props) {
return (
<Modal
animationType="slide"
transparent={true}
visible={props.isModalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Hello World!</Text>
<TouchableHighlight
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
props.setModalVisible(!props.isModalVisible);
}}
>
<Text style={styles.textStyle}>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}

Webview Uri Redirect by scanning barcodes with React Native, Expo

I am creating a barcode scanner using React Native and Expo.
I am trying to pass a new URL to a WebView after scanning a barcode.
But I am not sure how.
Please help.
export default function App() {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
setModalVisible(true);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View
style={{
flex: 1,
flexDirection: 'column'
}}>
<Modal
animationType="slide"
transparent={false}
visible={modalVisible}
onRequestClose={() => {
setScanned(false);
}}>
<View style={{ flex: 1 }}>
<WebView
style={{ flex: 1 }}
source={{ uri: 'http://domain.biz/' }}
/>
<TouchableHighlight
style={{
backgroundColor:'black',
padding: 15,
alignItems: 'center'
}}
onPress={() => {
setModalVisible(!modalVisible);
setScanned(false);
}}
underlayColor='slategray'
>
<Text style={{ color:'white', fontSize: 15 }}>Re Scan</Text>
</TouchableHighlight>
</View>
</Modal>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<View style={{ marginBottom: 100 }}>
<View style={{ alignItems: 'center', marginBottom: 5 }}>
<Image
style={{
width: 100,
height: 100,
resizeMode: 'contain',
marginBottom: 20,
}}
source={{ uri: 'http://domain.biz/img/logo_dark.png' }}
/>
<Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold', paddingBottom: 10}}>
QR Code Reader v0.5
</Text>
</View>
<View
style={{
borderColor: 'white',
borderTopWidth: 5,
borderBottomWidth: 5,
borderLeftWidth: 1,
borderRightWidth: 1,
paddingVertical: 80,
paddingHorizontal: 100,
}}
/>
<View style={{ alignItems: 'center', marginTop: 5 }}>
<Text style={{ color: 'white', fontSize: 15}}>
QR Scan...
</Text>
</View>
</View>
</BarCodeScanner>
</View>
);
}
I am creating a barcode scanner using React Native and Expo.
I am trying to pass a new URL to a WebView after scanning a barcode.
But I am not sure how.
Please help.
This should do the work. I save the url from the scanner in state.uri and use that instead of a static string.
For testing purposes I used this barcode which leads to this answer:
Best, Paul
import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Button, Modal, TouchableHighlight, Image } from 'react-native';
import { WebView } from 'react-native-webview';
import { BarCodeScanner } from 'expo-barcode-scanner';
export default function App(){
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(true);
const [modalVisible, setModalVisible] = useState(true);
const [uri, setUri] = useState('https://stackoverflow.com/questions/61977154/webview-uri-redirect-by-scanning-barcodes-with-react-native-expo');
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
setModalVisible(true);
// console.warn("Scan returned " + data);
setUri({ uri: data })
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View
style={{
flex: 1,
flexDirection: 'column'
}}>
<Modal
animationType="slide"
transparent={false}
visible={modalVisible}
onRequestClose={() => {
setScanned(false);
}}>
<View style={{ flex: 1 }}>
<WebView
style={{ flex: 1 }}
source={{uri: uri['uri']}}
/>
<TouchableHighlight
style={{
backgroundColor:'black',
padding: 15,
alignItems: 'center'
}}
onPress={() => {
setModalVisible(!modalVisible);
setScanned(false);
}}
underlayColor='slategray'
>
<Text style={{ color:'white', fontSize: 15 }}>Re Scan</Text>
</TouchableHighlight>
</View>
</Modal>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<View style={{ marginBottom: 100 }}>
<View style={{ alignItems: 'center', marginBottom: 5 }}>
<Image
style={{
width: 100,
height: 100,
resizeMode: 'contain',
marginBottom: 20,
}}
source={{ uri: 'http://domain.biz/img/logo_dark.png' }}
/>
<Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold', paddingBottom: 10}}>
QR Code Reader v0.5
</Text>
</View>
<View
style={{
borderColor: 'white',
borderTopWidth: 5,
borderBottomWidth: 5,
borderLeftWidth: 1,
borderRightWidth: 1,
paddingVertical: 80,
paddingHorizontal: 100,
}}
/>
<View style={{ alignItems: 'center', marginTop: 5 }}>
<Text style={{ color: 'white', fontSize: 15}}>
QR Scan...
</Text>
</View>
</View>
</BarCodeScanner>
</View>
);
}
Here it is, but I have passed the data from the other page name:index.js.
You can use the linking component to open every URL passed through {data}
import React from "react";
import { View, Text, Linking, TouchableOpacity } from "react-native";
const detail = ({ route, navigation }) => {
const data = route.params;
const [uri, setUri] = React.useState({});
return (
<View>
<TouchableOpacity onPress={() => Linking.openURL(data)}>
<Text>{data}</Text>
</TouchableOpacity>
</View>
);
};
export default detail;