how do you recognize touch events on react native webview? - react-native

Why is longpress event not recognizing the long press event? I have also used gestureHandler component and both are not working.
Can any one point me to relevant documentation or tell me why this code is not recognizing touchevents on the webview component.
export default function SiteCard({route, navigation}) {
const { site } = route.params;
const [urls, setUrls] = useState({
url2: site,
})
const webViewRef = useRef();
const onLongPress = (event) => {
if (event.nativeEvent.state === State.ACTIVE) {
alert("I've been pressed for 800 milliseconds");
}
};
return (
<LongPressGestureHandler
onHandlerStateChange={onLongPress}
minDurationMs={200}
>
<ScrollView scrollEnabled={false}
style={styles.tab}
level='1'>
<View>
<WebView
source={{ uri: urls.url2 }}
style={styles.PageView}
ref={webViewRef}
/>
</View>
</ScrollView>
</LongPressGestureHandler>
);
};
const styles = StyleSheet.create({
PageView: {
height: 800,
}
});

Related

How does onBlur event work in react native? it doesn't work i want it to

I made an expo app.
I want to make an AutoCompleteInput.
When focusing and changing TextInput, It will render the same words.
When ListItem clicks, TextInput's value will update it and it doesn't render.
When TextInput focus out, ListItem doesn't render.
In my code, the onPress event works first. onPress event works after.
how can i do?
and how does work onBlur event?
i moved onBlur event other component, but it doesn't work...
// App.js
...
return (
<View style={styles.container}>
<View style={styles.contentContainer}>
<Text>my content</Text>
</View>
<AutoInput />
<StatusBar style="auto" />
</View>
);
// AutoInput.jsx
import { ListItem, TextInput } from '#react-native-material/core';
import { useCallback, useState } from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';
import { locations } from '../../utils/constants';
const initialLocation = locations.map(({ name }) => name);
const AutoInput = () => {
const [location, setLocation] = useState('');
const [searchedLocations, setSearchedLocations] = useState([]);
const handleChangeInputText = useCallback(
(newString) => {
setLocation(newString);
if (!newString) {
setSearchedLocations(initialLocation);
return;
}
const filteredLocations = locations
.filter(({ name }) => name.includes(newString))
.map(({ name }) => name);
setSearchedLocations(filteredLocations);
},
[initialLocation]
);
return (
<View style={styles.container}>
<TextInput
placeholder="지역을 검색해주세요"
onBlur={() => {
console.log('blur');
setSearchedLocations([]);
}}
onFocus={() => console.log('focus')}
onChangeText={handleChangeInputText}
value={location}
/>
<ScrollView style={styles.scroll}>
{searchedLocations.map((searchLocation) => (
<ListItem
key={searchLocation}
title={searchLocation}
onPress={() => alert(searchLocation)}
style={styles.listItem}
/>
))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: { position: 'absolute', width: '100%' },
scroll: { maxHeight: 300 },
listItem: { width: '100%' },
});
export default AutoInput;
enter image description here

(react-native)There is a splash image that I drew, and I want to increase the time it takes to appear

The picture file I drew is in ASSETS
You can tell from this picture
I want to set the time when this image appears
I don't know much about coding because I'm a beginner
I want you to modify my whole code
I really want to complete this app
Please help me
I want to make the splash image appear for about 5 seconds
import React, { useRef, useState, useCallback, useEffect } from "react";
import { BackHandler, Platform, StyleSheet,ActivityIndicator } from "react-native";
import { WebView } from "react-native-webview";
export default function App() {
const webView = useRef();
const [canGoBack, setCanGoBack] = useState(false);
const handleBack = useCallback(() => {
if (canGoBack && webView.current) {
webView.current.goBack();
return true;
}
return false;
}, [canGoBack]);
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", handleBack);
return () => {
BackHandler.removeEventListener("hardwareBackPress", handleBack);
};
}, [handleBack]);
const App = () => (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator />
<ActivityIndicator size="large" />
<ActivityIndicator size="small" color="#0000ff" />
<ActivityIndicator size="large" color="#00ff00" />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around',
padding: 10,
},
});
const platformStyles = StyleSheet.create({
webView: Platform.OS === 'ios'
? { marginTop: 30, marginBottom: 40 }
: { marginTop: 30 }
});
return (
<WebView
ref={webView}
source={{ uri: "https://www.talesrunnerbestguild.co.kr/" }}
style = {platformStyles.webView}
onLoadProgress={(event) => setCanGoBack(event.nativeEvent.canGoBack)}
/>
);
}
So what you can do is once your splash image appears finish then launch default View where you can show splash image for 5 seconds, which you can set timer. Then navigate to another screen whichever you want to show after your timer time end ie after 5 seconds.
As You are using expo. You can achieve it by using expo-splash-screen function SplashScreen.preventAutoHideAsync() and SplashScreen.hideAsync()
Install expo-splash-screen in your project root.
expo install expo-splash-screen
Here is what you need to add to your code. I modify it from above expo guide
export default function App() {
...
const [appIsReady, setAppIsReady] = useState(false)
async function preventSplashHide() {
try {
// Manually stop hiding the splash screen
await SplashScreen.preventAutoHideAsync()
// 5 second timer
await new Promise(resolve => setTimeout(resolve, 5000))
} finally {
setAppIsReady(true);
}
}
// call preventSplashHide() when mount
useEffect(() => {
preventSplashHide()
}, [])
const hideSplash = useCallback(async () => {
if (appIsReady) {
// hide the splash screen when root view is shown(when appIsReady is true)
await SplashScreen.hideAsync()
// meanwhile the callback is listening on appIsReady
}
}, [appIsReady])
if (!appIsReady) {
return null
}
return (
<View
onLayout={hideSplash}>
...
</View>
);
}

How to give permission to access camera photo library in visual studio code for a ReactNative Iphone App

I want to know how to give permission to access camera photo library in visual studio code for a ReactNative Iphone App?
Here is my code:
FeedBackScreen.js:
import React,{Component} from 'react';
import {View,Text, StyleSheet,FlatList,Dimensions,TouchableOpacity,Image} from 'react-
native';
import {ActionSheet,configuration,onSelect,Root,options} from 'native-base';
import ImagePicker from 'react-native-image-crop-picker';
const width = Dimensions.get('window').width;
export default class FeedBackScreen extends Component{
constructor(props){
super(props);
this.state = {
fileList:[]
}
}
onSelectedImage = (image) =>{
let newDataImg = this.state.fileList;
const source = {uri:image.path};
let item = {
id:Date.now(),
url:source,
content:image.content
}
newDataImg.push(item);
this.setState({fileList:newDataImg})
};
takePhotoFromCamera = () =>{
ImagePicker.openPicker({
width:300,
height:400,
cropping:true
}).then(image =>
{
this.onSelectedImage(image);
console.log(image);
})
};
choosePhotoFromLibrary = () =>{
ImagePicker.openPicker({
width:300,
height:400,
cropping:true
}).then(image =>{
this.onSelectedImage(image);
console.log(image);
})
};
onClickAddPhoto = () => {
const BUTTONS = ['Take Photo', 'Choose Photo Library', 'Cancel'];
ActionSheet.show({
options: BUTTONS,
cancelButtonIndex: 2,
title: 'Select a Photo'
},
buttonIndex => {
switch (buttonIndex) {
case 0:
this.takePhotoFromCamera();
break;
case 1:
this.choosePhotoFromLibrary();
break;
default:
break;
}
})
}
renderItem = ({item,index}) =>{
return(
<View>
<Image
source={item.url}
style={styles.itemImage}
/>
</View>
)
};
render(){
let {content,btwPressStyle} = styles;
let {fileList } = this.state;
return(
<Root>
<View style={content}>
<Text>Sample React Native Add Image</Text>
<FlatList
data={fileList}
renderItem={this.renderItem}
keyExtractor={(item,index) => index.toString()}
extraData={this.state}
/>
<TouchableOpacity onPress={this.onClickAddPhoto}
style={styles.btwPressStyle}>
<Text>Add Photo</Text>
</TouchableOpacity>
</View>
</Root>
)
}
};
const styles = StyleSheet.create({
content:{
flex:1,
alignItems:'center',
marginTop:50
},
btwPressStyle:{
backgroundColor:'blue',
height:50,
width:100,
alignItems:'center'
},
itemImage:{
backgroundColor:'#2F455C',
height:150,
width:width-60,
borderRadius:8,
resizeMode:'contain'
}
})
After running this it is giving the following error:
TypeError:null is not an object(evaluating '_reactNativeImageCropPicker.default.openPicker')
Can you please help me with the directions of how to give permission?Thanks in Advance.

How Reload WebView on react navigation

How I can reload a webview to initial source when I click on button from navigator?
I can reset a original componet using?
React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', e => {
});
Or I can reload the webview on component?
function TabOneNavigator({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', e => {
alert('Default behavior prevented');
});
return unsubscribe;
}, [navigation]);
return (
<TabOneStack.Navigator>
<TabOneStack.Screen
name="Perfil"
component={TabOneScreen}
options={{ headerTitle: 'IzyJob' }}
/>
</TabOneStack.Navigator>
);
}
my screen
export default class App extends React.Component {
state = {
url: 'https://www.google.com'
};
render() {
return <WebView
source={{ uri: this.state.url }}
style={{ marginTop: 0 }} />;
}
}
My idea is when page on webview is different of state.url and has a click on tab navigation I reload to initial url
First create reference for the webview, like given below
<WebView
ref={(ref) => { this.webview = ref; }}
source={{ uri: this.state.url }}
style={{ marginTop: 0 }} />;
Then call this.webview.reload() where you want, this code will help you to refresh your webview

Pause video in flatlist when out of view

I have a flatlist showing videos. I want that when a video goes out of the view it should be paused. I am maintaining the pause state in each of the Posts component.
class Posts extends React.PureComponent {
constructor() {
super()
this.state = {
pause: true,
}
return(){
<Video
pause={this.state.pause}
//other props
/>
}
}
I am using react-native-video.
I have tried using onViewableItemsChanged prop of Flatlist but it doesn't change the state.
I tried this .
But it doesn't seem to work for me.
How should I proceed ?
Here is a possible solution using react-native-inviewport. This dependency is only a single index file that contains a component that has a callback when view is in the viewport. It could easily be modified to suit your needs.
I have constructed a very simple app that has a FlatList. The 11th item in the FlatList is a video. That should mean that the video is off the screen when the App renders so the viddeo won't be playing, once the video comes fully into the viewport it should then start playing.
App.js
import * as React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import VideoPlayer from './VideoPlayer';
export default class App extends React.Component {
state = {
data: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
}
renderItem = ({item, index}) => {
if (index === 10) {
return <VideoPlayer />
} else {
return (
<View style={{height: 100, backgroundColor: '#336699', justifyContent: 'center', alignItems: 'center'}}>
<Text>{index}</Text>
</View>
)
}
}
keyExtractor = (item, index) => `${index}`;
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});
VideoPlayer.js
This is a component that contains the Video component. The video is wrapped in the InViewPort component that has a callback function. The callback returns true when the component it surrounds is completely in the viewport and false when it is not fully in the viewport. The callback calls this.handlePlaying which in turn calls either this.playVideo or this.pauseVideo depending on the boolean value.
import React, {Component} from 'react';
import { View, StyleSheet } from 'react-native';
import { Video } from 'expo-av';
import InViewPort from './InViewPort';
//import InViewPort from 'react-native-inviewport; // this wouldn't work in the snack so I just copied the file and added it manually.
export default class VideoPlayer extends React.Component {
pauseVideo = () => {
if(this.video) {
this.video.pauseAsync();
}
}
playVideo = () => {
if(this.video) {
this.video.playAsync();
}
}
handlePlaying = (isVisible) => {
isVisible ? this.playVideo() : this.pauseVideo();
}
render() {
return (
<View style={styles.container}>
<InViewPort onChange={this.handlePlaying}>
<Video
ref={ref => {this.video = ref}}
source={{ uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay
style={{ width: 300, height: 300 }}
/>
</InViewPort>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
}
});
Here is a snack showing it working https://snack.expo.io/#andypandy/video-only-playing-when-in-viewport
I should point out that if the video is not fully in the viewport then it will not play. I am sure some tweaking could be done to react-native-inviewport so that it would play the video if it was partially in the viewport if that is what you wanted, perhaps by passing the height of the video to the InViewPort component.
here is how i simply did the trick
inside my card component that have video
<Video ...
paused={currentIndex !== currentVisibleIndex}
/>
both currentIndex and currentVisibleIndex are passed the component from the FlatList parent
my FlatList pass the renderItem index as currentIndex
<FlatList
data={[...]}
renderItem={({ item, index }) => (
<GalleryCard
{...item}
currentIndex={index}
currentVisibleIndex={currentVisibleIndex}
/>
)}
onViewableItemsChanged={this.onViewableItemsChanged}
viewabilityConfig={{
viewAreaCoveragePercentThreshold: 90
}}
finally my this is how to calculate currentVisibleIndex
please make sure to read viewabilityConfig
onViewableItemsChanged = ({ viewableItems, changed }) => {
if (viewableItems && viewableItems.length > 0) {
this.setState({ currentVisibleIndex: viewableItems[0].index });
}
};
please let me know if this is helpful
I finally did this using redux. Not sure whether it is the right way.
Home.js
_renderItem = ({item, index}) => <Posts item={item} />
viewableItemsChanged = (props) => {
let {changed} = props;
let changedPostArray = [];
changed.map((v,i) => {
let {isViewable, item} = v;
if(!isViewable) {
let {post_id, type} = item;
if(type === 1)
changedPostArray.push(post_id);
}
});
if(changedPostArray.length != 0)
this.props.sendPostToPause(changedPostArray);
}
render() {
return(
<View style={{flex: 1}} >
<FlatList
ref={(ref) => this.homeList = ref}
refreshing={this.state.refreshing}
onRefresh={async () => {
await this.setState({refreshing: true, postsId: [0], radiusId: 0, followingId: 0});
this.getPosts();
}}
onEndReached={async () => {
if(!this.state.isEnd) {
await this.setState({isPaginate: true})
this.getPosts()
}
}}
onEndReachedThreshold={0.2}
removeClippedSubviews={true}
contentContainerStyle={{paddingBottom: 80}}
data={this.state.followersRes}
renderItem={this._renderItem}
viewabilityConfig={this.viewabilityConfig}
onViewableItemsChanged={this.viewableItemsChanged}
/>
</View>
<Footer callback={this.scrollToTopAndRefresh} />
</View>
)
}
export default connect(null, {sendPostToPause})(Home);
Posts.js
class Posts extends React.PureComponent {
constructor(){
super()
this.state: {
pause: false
}
}
componentDidUpdate(prevProps) {
if(prevProps != this.props) {
this.props.postIdArray.map((v) => {
if(v === prevProps.item.post_id) {
this.setState({pause: true})
}
})
}
}
render(){
return(
<Video
pause={this.state.pause}
//Other props
/>
)
}
}
const mapStateToProps = (state) => {
const {postId} = state.reducers;
return {
postIdArray: postId
}
}
export default connect(mapStateToProps, {sendPostToPause})(withNavigation(Posts));
Whenever the viewableItemsChanged is trigger I am adding the changed posts id in an array and calling the action with the array of post ids.
In the Posts component I am checking if the post ids match, if so I am setting the pause state to true.