react native Image picker opens keyboard after selecting the Image? - ios

In my react native application I have used react native image picker but when I successfully select an image or take a picture from the camera it is opening the keyboard. This is how I have organised my code this problem only occurs in ios.
const openPicker = async (type, setFileObject, question, setImages, images) => {
// if (setImages && images) {
// setImages(null);
// }
var options;
if (type === 4) {
options = {
title: strings('picker.q-i-pick'),
takePhotoButtonTitle: strings('picker.tphoto'),
chooseFromLibraryButtonTitle: strings('picker.cgallery'),
cancelButtonTitle: strings('picker.cancel'),
mediaType: 'photo',
quality: 1,
storageOptions: {
skipBackup: true,
path: 'images',
},
};
}
if (type === 5) {
options = {
title: strings('picker.q-v-pick'),
takePhotoButtonTitle: strings('picker.tphoto'),
chooseFromLibraryButtonTitle: strings('picker.cgallery'),
cancelButtonTitle: strings('picker.cancel'),
mediaType: 'video',
durationLimit: question.question.duration,
videoQuality: Platform.OS === 'android' ? 'high' : 'high',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
}
if (type === 3) {
options = {
title: strings('picker.q-v-pick'),
takePhotoButtonTitle: strings('picker.tphoto'),
chooseFromLibraryButtonTitle: strings('picker.cgallery'),
cancelButtonTitle: strings('picker.cancel'),
mediaType: 'video',
durationLimit: question.question.duration,
videoQuality: Platform.OS === 'android' ? 'high' : 'high',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.launchCamera(options, (response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
// RNFetchBlob.fs.readFile(response.path, 'base64').then((data) => {
// response['data'] = data;
// response['type'] = 'mp4';
// response['fileName'] = 'videomulti.mp4';
// setFileObject(response);
// });
response['type'] = 'video/mp4';
response['fileName'] = 'videomulti.mp4';
setFileObject(response);
}
});
}
if (type === 4 || type === 5) {
ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
if (type === 4) {
setFileObject(response);
}
if (type === 5) {
console.log(response);
response['type'] = 'video/mp4';
response['fileName'] = 'videomulti.mp4';
setFileObject(response);
// RNFetchBlob.fs.readFile(response.path, 'base64').then((data) => {
// response['data'] = data;
// response['type'] = 'mp4';
// response['fileName'] = 'videomulti.mp4';
// setFileObject(response);
// });
}
}
});
}
};
I am calling this function inside the component like this.
const DocumentUpload = (props) => {
const { type, fileObject, setfilename, question } = props;
let [isVisible, setIsVisible] = useState(false);
const [uploded, setUploded] = useState(false);
const [state, setState] = useState({
fullscreen: false,
play: false,
currentTime: 0,
duration: 0,
showControls: true,
});
const [images, setImages] = useState(null);
useEffect(() => {
if (fileObject && fileObject.length !== 0 && type === 4) {
let imageArr = [];
let imageItem;
fileObject.map((item, index) => {
imageItem = {
ilustration: item.uri,
};
imageArr.push(imageItem);
});
setImages(imageArr);
}
}, [fileObject, type]);
const player = createRef();
return (
<View>
{(type === 5 || type === 3) && fileObject && fileObject.length !== 0 && (
<View style={styles.videoContainer}>
<View style={styles.videoInnerContainer}>
<TouchableWithoutFeedback
onPress={() => showControls(state, setState)}>
<View style={{ flex: 1 }}>
<Video
source={{
uri: fileObject[0].path,
}}
controls={false}
style={styles.backgroundVideo}
ref={player}
resizeMode={'contain'}
paused={!state.play}
onEnd={() => onEnd(state, setState, player)}
onLoad={(data) => onLoadEnd(data, state, setState)}
onProgress={(data) => onProgress(data, state, setState)}
/>
{state.showControls && (
<View style={styles.controlsOverlay}>
<PlayerControls
play={state.play}
playVideo={handlePlayPause}
state={state}
setState={setState}
pauseVideo={handlePlayPause}
/>
</View>
)}
</View>
</TouchableWithoutFeedback>
</View>
</View>
)}
{type === 4 && fileObject && fileObject.length !== 0 && images && (
<View style={{ alignItems: 'center', height: '70%' }}>
<ImageCarousel images={images} uploadedImages={true} />
</View>
)}
{type === 4 && fileObject && !images && (
<View style={styles.loadderContainerWI}>
<Image source={spinner} resizeMode={'center'} />
</View>
)}
{!fileObject || fileObject.length === 0 ? (
<>
<TouchableOpacity
onPress={
// () => setIsVisible(true)
() => openPicker(type, setfilename, question)
}>
<Image
source={Platform.OS === 'android' ? require('_assets/img/cmerap.png') : require('_assets/img/cmerapios.png')}
resizeMode={Platform.OS === 'android' ? "center" : "center"}
style={Platform.OS === 'android' ? styles.camPImageWV : styles.camPImageWVIos}
/>
</TouchableOpacity>
<AppText styles={styles.camPTextIos}>
{strings('assetsment.capture')}
</AppText>
</>
) : (
<>
{type === 4 && images && (
<View
style={[
styles.videoBottomText,
images ? { marginTop: '9%' } : null,
]}>
<TouchableOpacity
onPress={
// () => setIsVisible(true)
() =>
openPicker(type, setfilename, question, setImages, images)
}>
<View style={styles.updateAgainContainer}>
<AntIcon name="reload1" style={styles.reloadIcon} />
<AppText styles={styles.reloadText}>
{strings('assetsment.reload')}
</AppText>
</View>
</TouchableOpacity>
</View>
)}
{(type === 5 || type === 3) && (
<View style={styles.videoBottomText}>
<TouchableOpacity
onPress={
// () => setIsVisible(true)
() =>
openPicker(type, setfilename, question, setImages, images)
}>
<View style={styles.updateAgainContainer}>
<AntIcon name="reload1" style={styles.reloadIcon} />
<AppText styles={styles.reloadText}>
{strings('assetsment.reload')}
</AppText>
</View>
</TouchableOpacity>
</View>
)}
</>
)}
</View>
);
};
After selecting the image and then close the picker in ios it is opening the keyboard even there is no any input field in that component but it only happens in first Time of image selection second time it is not happening. So can someone help me with this one? I tried to dismiss the keyboard manually by calling keyboard.dismiss() after selecting the image but that also gone in-vain. Thank you

Related

ReactNative : Getting white space between keyboard and comment-box input field

I am getting white space between the keyboard and input box. I have used KeyBoardAvoiding view in my code.
Here is the piece of code:
const [isKeyboardVisible, setKeyboardVisible] = useState(false);
const [offsetValue, setOffsetValue] = useState(0);
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener("keyboardDidShow", () => {
setKeyboardVisible(true);
});
const keyboardDidHideListener = Keyboard.addListener("keyboardDidHide", () => {
setKeyboardVisible(false);
});
if (appState === "active") {
isKeyboardVisible && Keyboard.dismiss();
}
return () => {
keyboardDidHideListener.remove();
keyboardDidShowListener.remove();
};
}, []);
useEffect(() => {
if (isKeyboardVisible) {
setOffsetValue(0);
} else {
setOffsetValue(80);
}
}, [isKeyboardVisible]);
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
keyboardVerticalOffset={Platform.OS === "ios" ? offsetValue : 0}
>
<ScrollView
contentContainerStyle={styles.scrollViewContainer}
alwaysBounceVertical={false}
keyboardShouldPersistTaps={"handled"}
>
<View style={styles.chatInputBoxWrapper}>
<AvyCommentLinearInput
inputRef={props.setInputRef}
value={props.inputValue}
isVideoCaptureEnabled={true}
imageUrl={""}
onSubmit={(value) => props.onChatSubmit(value)}
/>
</View>
</ScrollView>
</KeyboardAvoidingView>
export default StyleSheet.create({
scrollViewStyle: {
marginHorizontal: 16,
borderRadius: 4,
marginBottom: 8,
marginTop: 8,
},
chatInputBoxWrapper: {
...shadowStyle,
flex: 1,
},
scrollViewContainer: { flexGrow: 1 },
});
Video link of the issue I am facing:
https://www.dropbox.com/s/6ydwxhaq06dpfaf/RPReplay_Final1674132226.MP4?dl=0
Any help would be Appreciated!!!
My recommendation - use React Native Avoid SoftInput https://mateusz1913.github.io/react-native-avoid-softinput/
A lot of examples https://github.com/mateusz1913/react-native-avoid-softinput/tree/main/packages/app/src/screens

ReactNative ble manager is not reading data from peripheral on IOS

I am building a ReactNative application for both IOS and Android platforms. My app needs to read data from another device via BLE communication. I am using this package for implementing BLE communication, https://github.com/innoveit/react-native-ble-manager. I am having a problem with receiving characteristic data on IOS even though it is working as expected on the Android platform.
I have added the following to the info.plist file:
Privacy - Bluetooth Always Usage Description: App needs to use Bluetooth to receive data from WaterRower machine
I have a component that scan and list down the BLE devices as follow. It is called, BleDeviceList.js
import React, {
useState,
useEffect,
} from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
NativeModules,
NativeEventEmitter,
Button,
Platform,
PermissionsAndroid,
FlatList,
TouchableHighlight,
} from 'react-native';
import {
Colors,
} from 'react-native/Libraries/NewAppScreen';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const BleDeviceList = (props) => {
const [isScanning, setIsScanning] = useState(false);
const peripherals = new Map();
const [list, setList] = useState([]);
const [ connectedDevices, setConnectedDevices ] = useState([ ]);
const [ permissionsAllowed, setPermissionsAllowed ] = useState(false)
const startScan = () => {
if (!isScanning) {
BleManager.scan([], 3, true).then((results) => {
console.log('Scanning...');
setIsScanning(true);
}).catch(err => {
console.error(err);
});
}
}
const handleStopScan = () => {
console.log('Scan is stopped');
setIsScanning(false);
}
const handleDisconnectedPeripheral = (data) => {
let peripheral = peripherals.get(data.peripheral);
if (peripheral) {
peripheral.connected = false;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
console.log('Disconnected from ' + data.peripheral);
}
const handleUpdateValueForCharacteristic = (data) => {
console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value);
}
const retrieveConnected = () => {
BleManager.getConnectedPeripherals([]).then((results) => {
if (results.length == 0) {
console.log('No connected peripherals')
}
console.log(results);
for (var i = 0; i < results.length; i++) {
var peripheral = results[i];
peripheral.connected = true;
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
});
}
const handleDiscoverPeripheral = (peripheral) => {
console.log('Got ble peripheral', peripheral);
if (!peripheral.name) {
peripheral.name = 'NO NAME';
}
peripherals.set(peripheral.id, peripheral);
setList(Array.from(peripherals.values()));
}
const isConnected = (peripheral) => {
return connectedDevices.filter(cd => cd.id == peripheral.id).length > 0;
}
const toggleConnectPeripheral = (peripheral) => {
if (peripheral){
if (isConnected(peripheral)){
BleManager.disconnect(peripheral.id);
setConnectedDevices(connectedDevices.filter(cd => cd.id != peripheral.id))
}else{
BleManager.connect(peripheral.id).then(() => {
let tempConnnectedDevices = [ ...connectedDevices ]
tempConnnectedDevices.push(peripheral);
setConnectedDevices(tempConnnectedDevices);
props.navigation.push('BleRowingSession', { peripheral: peripheral });
let p = peripherals.get(peripheral.id);
if (p) {
p.connected = true;
peripherals.set(peripheral.id, p);
setList(Array.from(peripherals.values()));
props.navigation.push('BleDeviceServiceList', { peripheral: peripheral });
}
console.log('Connected to ' + peripheral.id);
}).catch((error) => {
console.log('Connection error', error);
});
}
}
}
useEffect(() => {
BleManager.start({showAlert: false});
bleManagerEmitter.addListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.addListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.addListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
if (Platform.OS === 'android' && Platform.Version >= 23) {
PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("Permission is OK");
setPermissionsAllowed(true);
} else {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
if (result) {
console.log("User accept");
setPermissionsAllowed(true);
} else {
console.log("User refuse");
setPermissionsAllowed(false);
}
});
}
});
} else {
setPermissionsAllowed(true)
}
return (() => {
console.log('unmount');
bleManagerEmitter.removeListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.removeListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.removeListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.removeListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
})
}, []);
const renderConnectButton = (item) => {
if (isConnected(item)) {
return null
}
return (
<Button
title="Connect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderDisconnectButton = (item) => {
if (! isConnected(item)) {
return null
}
return (
<Button
title="Disconnect"
onPress={() => {
toggleConnectPeripheral(item)
}}
/>
)
}
const renderItem = (item) => {
const color = item.connected ? 'green' : '#fff';
return (
<TouchableHighlight>
<View style={[styles.row, {backgroundColor: color}]}>
<Text style={{fontSize: 12, textAlign: 'center', color: '#333333', padding: 10}}>{item.name}</Text>
<Text style={{fontSize: 10, textAlign: 'center', color: '#333333', padding: 2}}>RSSI: {item.rssi}</Text>
<Text style={{fontSize: 8, textAlign: 'center', color: '#333333', padding: 2, paddingBottom: 20}}>{item.id}</Text>
{renderConnectButton(item)}
{renderDisconnectButton(item)}
</View>
</TouchableHighlight>
);
}
const renderContent = () => {
if (! permissionsAllowed) {
return <Text>Bluetooth and locations permissions are required.</Text>
}
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
{global.HermesInternal == null ? null : (
<View style={styles.engine}>
<Text style={styles.footer}>Engine: Hermes</Text>
</View>
)}
<View style={styles.body}>
<View style={{margin: 10}}>
<Button
title={'Scan Bluetooth (' + (isScanning ? 'on' : 'off') + ')'}
onPress={() => startScan() }
/>
</View>
<View style={{margin: 10}}>
<Button title="Retrieve connected peripherals" onPress={() => retrieveConnected() } />
</View>
{(list.length == 0) &&
<View style={{flex:1, margin: 20}}>
<Text style={{textAlign: 'center'}}>No peripherals</Text>
</View>
}
</View>
</ScrollView>
<FlatList
data={list}
renderItem={({ item }) => renderItem(item) }
keyExtractor={item => item.id}
/>
</SafeAreaView>
</>
)
}
return (
renderContent()
);
};
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});
export default BleDeviceList;
As you can see in the code, when the Connect button is clicked, it will redirect the user to another component that reads data from another device. The following is the BleRowingSession.js that reads the data from another device.
import React, { useEffect, useState } from 'react';
import { Text, View, StyleSheet, NativeModules, NativeEventEmitter, ScrollView } from 'react-native';
import BleManager from 'react-native-ble-manager';
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
const serviceId = "00001826-0000-1000-8000-00805F9B34FB";
const characteristicId = "00002AD1-0000-1000-8000-00805F9B34FB";
let readDataCache = "";
const BleRowingSession = (props) => {
let peripheral = props.route.params.peripheral;
const [ readData, setReadData ] = useState("");
const setUpBleNotification = () => {
BleManager.retrieveServices(peripheral.id).then((peripheralData) => {
console.log('Retrieved peripheral services', peripheralData);
setTimeout(() => {
BleManager.startNotification(peripheral.id, serviceId, characteristicId).then(() => {
console.log('Started notification on ' + peripheral.id);
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', (data) => {
readDataCache = readDataCache + "\n" + data.value.toString()
setReadData(readDataCache);
});
setTimeout(() => {
}, 500);
}).catch((error) => {
console.log('Notification error', error);
});
}, 500)
});
}
useEffect(() => {
setUpBleNotification()
}, [ ])
return (
<View style={styles.container}>
<ScrollView>
<Text>Ble Rowing Session</Text>
<Text>{readData}</Text>
</ScrollView>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
})
export default BleRowingSession;
For now, the service id and characteristic id are hardcoded. Of course, I had to choose the right device on the first page that displays the list of BLE devices.
When I run the code, it is working as expected on the Android device, it is receiving the characteristic value. When I run the code on the actual IOS device, it is not receiving any data. But it can scan the devices and connect to them. What is wrong with my code and how can I fix it?

How to redirect or load a view depending upon condition in react-native-iap purchase

What I want to achieve is to redirect or show a view upon successful purchase. Purchase is successful but the state variable is not updating inside validateReceiptIos handler.
I checked the validation of the receipt but after that not even able to redirect to another page or load a view on the condition. I am attaching a code snippet below.
const productIds = ['xxx_xx_xx'];
const InAppPurchase = ({ navigation }) => {
const [products, setProducts] = useState([]);
const [purchased, setPurchased] = useState(false);
const [email, setEmail] = useState({
emailText: '',
emailValidity: false,
emailErrorText: null,
});
const [name, setName] = useState({
nameText: '',
nameValidity: false,
nameErrorText: null,
});
const validateUserName = (text) => {
if (text.length < 1) {
setName({ nameText: text, nameValidity: false, nameErrorText: 'Name cannot be empty' });
}
else { setName({ nameText: text, nameValidity: true, nameErrorText: '' }); }
};
const validateEmail = (text) => {
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (reg.test(text) === false && text.length > 0) {
setEmail({ emailText: text, emailValidity: false, emailErrorText: 'Invalid email' });
} else if (text.length < 1) {
setEmail({ emailText: text, emailValidity: false, emailErrorText: 'Email cannot be empty' });
}
else { setEmail({ emailText: text, emailValidity: true, emailErrorText: '' }); }
};
const validate = async (receipt, purchase) => {
const receiptBody = {
"receipt-data": receipt,
"password": "xxxxxxxxxxxxxxxxxxxxxx"
}
const result = await IAP.validateReceiptIos(receiptBody, true).catch(() => {
}).then((receipt) => {
try {
const renewalHistory = receipt.latest_receipt_info;
const expiration = renewalHistory[renewalHistory.length - 1].expires_date_ms;
// const expiration = renewalHistory[0].expires_date_ms;
let expired = Date.now() > expiration;
if (!expired) {
IAP.finishTransaction(purchase);
setPurchased(true); //***Not updating the state variable***
//navigation.navigate('Success') //***Not even navigate to another page***
} else {
Alert.alert("Purchase expired", "Your subscription has been expired, please resubscribe to continue using the app")
}
} catch (error) {
console.log(error)
}
})
}
useEffect(() => {
IAP.getProducts(productIds).then(res => {
setProducts(res);
})
const purchaseUpdateSubscription = IAP.purchaseUpdatedListener(purchase => {
const receipt = purchase.transactionReceipt;
if (receipt) {
validate(receipt, purchase)
}
})
return () => {
purchaseUpdateSubscription.remove();
}
}, []);
if (purchased) {
return (
<SafeAreaView style={styles.container}>
<View style={styles.containerInner}>
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={styles.logoSuccessSection}>
<Image style={styles.successLogo} source={require('../images/success.png')} />
</View>
<View style={{ flex: 1 }}>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Login')}>
<Text style={styles.signText}>CONTINUE</Text>
</TouchableOpacity>
</View>
</View>
</View>
</SafeAreaView>
)
} else {
return (
<SafeAreaView style={styles.container}>
<View style={styles.containerInner}>
<View style={styles.logoSection}>
<Image style={styles.logo} source={require('../images/logo.jpg')} />
</View>
<View style={styles.headerContainer}>
<Text style={styles.headerText}>PREMIUM ACCESS</Text>
</View>
<View style={styles.featureContainer}>
<ScrollView style={{ flexDirection: 'column', paddingVertical: 20 }}>
<TextInput blurOnSubmit={true} autoCapitalize='none' placeholderTextColor="#736c6c"
style={{ height: 40, borderColor: '#d6d8e1', borderWidth: 1, paddingHorizontal: 10 }} placeholder="Email" onChangeText={(text) => validateEmail(text)} onSubmitEditing={(event) => setEmail({ emailText: event.nativeEvent.text })}
/>
{email.emailValidity === false ? <Text style={styles.errorTextStyle}>{email.emailErrorText}</Text> : null}
<TextInput blurOnSubmit={true} autoCapitalize='none' placeholderTextColor="#736c6c"
style={{ height: 40, borderColor: '#d6d8e1', borderWidth: 1, paddingHorizontal: 10, marginVertical: 5 }} placeholder="Name" onChangeText={(text) => validateUserName(text)} onSubmitEditing={(event) => setName({ nameText: event.nativeEvent.text })}
/>
{name.nameValidity === false ? <Text style={styles.errorTextStyle}>{name.nameErrorText}</Text> : null}
</ScrollView>
</View>
<View>
{products.map((product, i) =>
<TouchableOpacity key={i} style={styles.button} onPress={() => {
if (email.emailValidity === false || name.nameValidity === false) {
Alert.alert(
"Email & Name fields cannot be empty.",
"",
[
{ text: "OK", onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
);
} else {
IAP.requestSubscription(product.productId);
}
}}>
<Text style={styles.signText}>SUBSCRIBE - $9.99/Month</Text>
</TouchableOpacity>
)}
</View>
</View>
</SafeAreaView>
)
}
}

go to view in animated.Scrollview

Using this code i try to add on each marker an onpress option
there is the source source and there is a sample of my work
after many try i give up ... is there a way to add on my onpress the x position to my Animated.ScrollView
when i scroll i can see the marker changing but i want to add an onpress function in each marker. when press one off the marker i want to the scrollview set to the position of my maker
componentWillMount() {
this.index = 0;
this.animation = new Animated.Value(0);
}
componentDidMount() {
// We should detect when scrolling has stopped then animate
// We should just debounce the event listener here
AsyncStorage.getItem('userToken', (err, result) => {
if (this.state.userToken == null) {
this.setState({ userToken: result })
this.GetAllMarker()
}
});
this.animation.addListener(({ value }) => {
console.log(value)
let index = Math.floor(value / CARD_WIDTH + 0.3); // animate 30% away from landing on the next item
if (index >= this.state.markers.length) {
index = this.state.markers.length - 1;
}
if (index <= 0) {
index = 0;
}
clearTimeout(this.regionTimeout);
this.regionTimeout = setTimeout(() => {
if (this.index !== index) {
this.index = index;
const { coordinates } = this.state.markers[index];
console.log(index)
this.map.animateToRegion(
{
...coordinates,
latitudeDelta: this.state.region.latitudeDelta,
longitudeDelta: this.state.region.longitudeDelta,
},
350
);
}
}, 10);
});
}
GenerateBearer() {
let tmp = `Bearer ` + this.state.userToken
tmp = tmp.replace('"', '');
tmp = tmp.replace('"', '');
return (tmp)
}
GetAllMarker() {
let Bearer = this.GenerateBearer();
console.log(Bearer)
fetch(Config.API_URL + "/api/public/user/aroundMe?latitude=" + this.state.region.latitude + "&longitude=" + this.state.region.longitude + "&rayon=50", {
method: 'GET',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json',
'Authorization': Bearer,
}
})
.then(res => res.json())
.then(res => {
this.setState({ markers: res })
})
.catch(error => {
this.setState({ error: error });
});
}
handleMarkerPress(e){
this.state.markers[1] = e
console.log(e)
}
render() {
const interpolations = this.state.markers.map((marker, index) => {
const inputRange = [
(index - 1) * CARD_WIDTH,
index * CARD_WIDTH,
((index + 1) * CARD_WIDTH),
];
const scale = this.animation.interpolate({
inputRange,
outputRange: [1, 2.5, 1],
extrapolate: "clamp",
});
const opacity = this.animation.interpolate({
inputRange,
outputRange: [0.35, 1, 0.35],
extrapolate: "clamp",
});
return { scale, opacity };
});
return (
<View style={styles.container}>
<MapView
ref={map => this.map = map}
initialRegion={this.state.region}
style={styles.container}
>
<UrlTile
urlTemplate="http://ip/styles/klokantech-basic/{z}/{x}/{y}.png"
zIndex={-1}
/>
{this.state.markers.map((marker, index) => {
const scaleStyle = {
transform: [
{
scale: interpolations[index].scale,
},
],
};
const opacityStyle = {
opacity: interpolations[index].opacity,
};
return (
<MapView.Marker key={index} coordinate={marker.coordinates} onPress={(event) => this.handleMarkerPress(index)} >
<Animated.View style={[styles.markerWrap, opacityStyle]} >
<Animated.View style={[styles.ring, scaleStyle]} />
<View style={styles.marker} />
</Animated.View>
</MapView.Marker>
);
})}
</MapView>
<Animated.ScrollView
horizontal
scrollEventThrottle={1}
showsHorizontalScrollIndicator={true}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event(
[{nativeEvent: {
contentOffset: {
x: this.animation,
},
},},],
{ useNativeDriver: true }
)}
style={styles.scrollView}
contentContainerStyle={styles.endPadding}
>
{this.state.markers.map((marker, index) => {
if (marker.isAlerte == false)
return (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.espace.titre}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>)
else
return (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.alerte.type}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>)
})
}
</Animated.ScrollView>
</View>
);
}
}
found the solution
Add
<Animated.ScrollView
horizontal
ref={(c) => {this.scroll = c}}
scrollEventThrottle={1}
showsHorizontalScrollIndicator={true}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event( [{ nativeEvent: { contentOffset: { x: this.animation, }, }, },], { useNativeDriver: true } )}
style={styles.scrollView}
contentContainerStyle={styles.endPadding} >
and this for the map view marker
<MapView.Marker
key={index}
coordinate={marker.coordinates}
onPress={() => this.handleMarkerPress(index)} >
and the handlemarkerpress
this.scroll.getNode().scrollTo({x: e * 375, y: 0, animated: true});
(375 for my card width)
To scroll to a position x,y in your scroll view. Use the scrollTo function in the scroll view. Checkout here the react native documentation about it https://facebook.github.io/react-native/docs/scrollview#scrollto.
Use the ref property to execute the method in your scrollview.
Now you need to identify the x and y of your markers so you can scroll to them. Never done something like that but here is an article of someone calculating the x and y of react native elements https://github.com/facebook/react-native/issues/1374.

React Native - Screen blinks when updating props in this.intervalHandle = setInterval

My problem is I want to update my data and display on screen in real time, but every time I try to update this.props.stoveUsage, my screen turns blank when I make the this.getUsage() call in this.intervalHandle = setInverval
This is where my problem occurs:
componentDidMount () {
console.log('Enter StatsScreen.componentDidMount')
this.drawer.drawer.setNativeProps({ style: { width: 0 } })
this.intervalHandle = setInterval(() => {
this.getUsage()
}, 30000)
}
this.getUsage is supposed to update the props in getStoveUsage: (deviceId, viewType, start) =>
dispatch(SmarturnsActions.getUsage(deviceId, viewType, start))
const mapDispatchToProps = (dispatch) => {
return {
selectDevice: (selectedDeviceId) =>
dispatch(SmarturnsActions.deviceSelected(selectedDeviceId)),
getStoveUsage: (deviceId, viewType, start) =>
dispatch(SmarturnsActions.getUsage(deviceId, viewType, start))
}
}
Full code here:
class Stats extends React.Component {
constructor (props) {
super(props)
this.state = {
viewType: 'day',
dt: moment(),
device: {},
updateFlipFlop: true
}
this.intervalHandle = null
}
static navigationOptions = {
tabBarLabel: I18n.t('$tab_usage'),
tabBarIcon: ({ tintColor, focused }) => {
return (
<Image
source={focused ? Images.tabStatsActive : Images.tabStats}
style={[styles.tabIcon, { tintColor: tintColor }]}
/>
)
}
}
getDevice = (selectedDeviceId) => {
const devices = this.props.devices || []
let dev = {}
devices.forEach((d) => {
if (d._id === selectedDeviceId) {
dev = d
}
})
if (!dev._id && devices.length) {
dev = devices[0]// dev is the device we are working with
}
this.setState({ device: dev }, () => {
this.getUsage()
})
}
componentDidMount () {
console.log('Enter StatsScreen.componentDidMount')
this.drawer.drawer.setNativeProps({ style: { width: 0 } })
this.intervalHandle = setInterval(() => {
this.getUsage()
}, 30000)
}
componentWillMount () {
console.log('Enter StatsScreen.componentWillMount')
this.getDevice(this.props.selectedDeviceId)
}
componentWillUnmount = () => {
console.log('Enter MainScreen.componentWillUnmount()')
if (this.intervalHandle) clearInterval(this.intervalHandle)
}
componentWillReceiveProps (nextProps) {
if (nextProps.selectedDeviceId !== this.props.selectedDeviceId) {
this.getDevice(nextProps.selectedDeviceId)
} else if (nextProps.stoveUsage !== this.props.stoveUsage) {
this.setState({ updateFlipflop: !this.state.updateFlipflop })
}
}
onPressPrev = () => {
console.log('onPressPrev')
console.log('state=', this.state)
const dt = moment(this.state.dt).add(-1, this.state.viewType + 's') // converts to 'days', 'weeks', 'months'
this.setState({ dt }, () => {
this.getUsage()
})
}
onPressNext = () => {
console.log('onPressNext')
const dt = moment(this.state.dt).add(1, this.state.viewType + 's') // converts to 'days', 'weeks', 'months'
this.setState({ dt }, () => {
this.getUsage()
})
}
onPressCalendar = () => {
console.log('onPressCalendar')
}
getUsage = () => {
let dt = this.state.dt
let vt = this.state.viewType
let dev = this.state.device
let date
if (vt === 'day') {
date = moment(dt).format('YYYY-MM-D')
} else if (vt === 'week') {
date = moment(dt).startOf('week').format('YYYY-MM-D')
} else {
date = moment(dt).format('YYYY-MM')
}
this.props.getStoveUsage(dev._id, vt, date)
}
onPressSegment = (viewType) => {
console.log('click on segment ', viewType)
this.setState({ viewType: viewType, dt: moment() }, () => {
this.getUsage()
})
}
_onStovePress = (stove) => {
console.log('Enter StatsScreen._onStovePress. stove=', stove._id)
this.props.selectDevice(stove._id)
this.closeDrawer()
}
formatDate = (dt) => {
if (this.state.viewType === 'day') {
return moment(dt).calendar(null, {
sameDay: '[Today]',
nextDay: '[Tomorrow]',
lastDay: '[Yesterday]',
lastWeek: 'ddd, MMM D',
sameElse: 'ddd, MMM D'
})
} else if (this.state.viewType === 'week') {
return moment(dt).startOf('week').format('MMM D') + ' - ' + moment(dt).startOf('week').add(6, 'days').format('MMM D')
} else {
return moment(dt).format('MMM, YYYY')
}
}
displayUsage = () => {
if (!this.props.fetching && this.props.stoveUsage) {
const total = moment.duration(this.props.stoveUsage.total, 'seconds').format('H:mm', {trim: false})
const average = this.props.stoveUsage.average
const usage = this.props.stoveUsage.usage
if (this.state.viewType === 'day') {
return <UsageDay totalUsage={total} average={average} usage={usage} date={this.state.dt} />
} else if (this.state.viewType === 'week') {
return <UsageWeek totalUsage={total} usage={usage} />
} else {
return <UsageMonth totalUsage={total} usage={usage} />
}
}
}
closeDrawer = () => {
this.drawer.close()
this.drawer.drawer.setNativeProps({ style: { width: 0 } })
}
openDrawer = () => {
this.drawer.drawer.setNativeProps({ style: { width: this.drawer.getDrawerWidth() } })
this.drawer.open()
}
_renderDrawer = (dev) => {
const allStoves = this.props.devices || []
const devices = allStoves.filter((d) => { return d.follower.enabled })
const selfStoves = devices.filter(d => !d.is_shared)
const sharedStove = devices.filter(d => !!d.is_shared)
return (
<ScrollView style={[styles.drawerContainer]}>
<View style={styles.drawerHeader} >
<Text style={{ color: '#fff' }}>{dev.owner_username}</Text>
</View>
<List>
<ListItem itemDivider>
<Text>{I18n.t('$setting_my_smarturns')}</Text>
</ListItem>
{
selfStoves.map(stove => (
<ListItem key={stove._id}
onPress={() => { this._onStovePress(stove) }} >
<Body>
<Text>{stove.name}</Text>
<Text note>{stove.owner_username}</Text>
</Body>
</ListItem>
))
}
<ListItem itemDivider>
<Text>{I18n.t('$setting_others_smarturns')}</Text>
</ListItem>
{
sharedStove.map(stove => (
<ListItem key={stove._id}
onPress={() => { this._onStovePress(stove) }} >
<Body>
<Text>{stove.name}</Text>
<Text note>{stove.owner_username}</Text>
</Body>
</ListItem>
))
}
</List>
</ScrollView>)
}
render () {
console.log('Enter StatsScreen.render()')
let dt = this.state.dt
if (this.state.viewType === 'week') dt = moment(dt).startOf('week')
const dateStr = this.formatDate(dt)
return (
<StyleProvider style={getTheme(commonColor)}>
<Container>
<Drawer ref={(ref) => { this.drawer = ref }}
type='overlay'
tapToClose
openDrawerOffset={0.3}
content={this._renderDrawer(this.state.device)}
onClose={() => this.closeDrawer()} >
<Header hasSubtitle>
<Left>
<Button transparent onPress={this.openDrawer}>
<Icon name='navicon' />
</Button>
</Left>
<Body >
<Title>{I18n.t('$usage_title')}</Title>
<Subtitle style={{ color: 'white' }} ellipsizeMode='tail' numberOfLines={1}>{this.state.device.name}</Subtitle>
</Body>
<Right />
</Header>
<Segment>
<Button first active={this.state.viewType === 'day'} onPress={() => this.onPressSegment('day')}><Text>Daily</Text></Button>
<Button active={this.state.viewType === 'week'} onPress={() => this.onPressSegment('week')}><Text>Weekly</Text></Button>
<Button last active={this.state.viewType === 'month'} onPress={() => this.onPressSegment('month')}><Text>Monthly</Text></Button>
</Segment>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', height: 40 }}>
<View>
<Button transparent onPress={this.onPressPrev}>
<Icon name='angle-left' style={{ color: 'rgba(46, 88, 137, 1)' }} />
</Button>
</View>
<View>
<Button transparent onPress={this.onPressCalendar}>
<Text note>{dateStr}</Text>
{/* <Icon name='calendar' /> */}
</Button>
</View>
<View>
<Right>
<Button transparent onPress={this.onPressNext}>
<Icon name='angle-right' style={{ color: 'rgba(46, 88, 137, 1)' }} />
</Button>
</Right>
</View>
</View>
<Content contentContainerStyle={{ flex: 1 }}>
{this.displayUsage()}
</Content>
</Drawer>
</Container>
</StyleProvider>
)
}
}
const mapStateToProps = (state) => {
return {
fetching: state.smarturns.fetching,
devices: state.smarturns.devices,
selectedDeviceId: state.smarturns.selectedDeviceId,
stoveUsage: state.smarturns.usage
}
}
const mapDispatchToProps = (dispatch) => {
return {
selectDevice: (selectedDeviceId) => dispatch(SmarturnsActions.deviceSelected(selectedDeviceId)),
getStoveUsage: (deviceId, viewType, start) => dispatch(SmarturnsActions.getUsage(deviceId, viewType, start))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Stats)

Resources