react native iOS can't open Camera/Gallery after first time - ios

This is my source code:
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
isVisible: false,
};
}
openModal = () => {
this.setState({isVisible: true});
}
openPicker = () => {
this.setState({isVisible: false});
ImagePicker.openPicker({
mediaType: "video",
}).then((video) => {
console.log(video);
});
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.openModal}>
<Text>Choose Image</Text>
</TouchableOpacity>
{
this.state.isVisible &&
<Modal style={styles.modal}>
<View style={styles.conModal}>
<TouchableOpacity style={styles.touch} onPress={this.openPicker}>
<Text style={styles.text}>Open Gallery</Text>
</TouchableOpacity>
</View>
</Modal>
}
</View>
);
}
}
When user tap "Choose Image" button, app will show "Choose Image" modal which allow user choose "Open Gallery" button or other buttons such as "Open Camera",...
After user choose "Open Gallery" button, app will close "Choose Image" modal by this.setState({isVisible: false}) before open Gallery.
It's working perfectly on Android. But it only work once time on iOS. Next time, app also show Gallery but it's closed immediately.
If i change logic to: open Gallery before close "Choose Image" modal by this.setState({isVisible: false}), it will work. But my customer don't accept it.
Please help me.
Thanks.

open gallery after some delay. I think it may work
openPicker = () => {
this.setState({isVisible: false});
// open gallery after some delay.
setTimeout(()=>{
ImagePicker.openPicker({
mediaType: "video",
}).then((video) => {
console.log(video);
});
},700) // you can change delay time as per your requirement
}

Related

React Native RefreshControl not triggering onRefresh on iOS

I've got the following (simplified) setup for my PersonScreen, which navigate to AppointmentScreen:
class PersonScreen {
state = {
refreshing: false,
};
_onRefresh = () => {
this.setState({ refreshing: true });
this._fetchStuff()
.then(() => {
this.setState({ refreshing: false });
};
};
render() {
return (
<View style={CONTAINER}>
<ScrollView
keyboardShouldPersistTaps="handled"
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={this._onRefresh} />}
<ListItem
key={ITEM.id}
title={moment(DATETIME).format(FORMAT))}
onPress={() => {
navigation.navigate('AppointmentScreen', {
appointment: ITEM,
refreshParent: this._onRefresh,
});
}
/>
</ScrollView>
</View>
);
}
}
On the AppointmentScreen you make some choices and then to go back the following is performed:
const { refreshParent } = navigation.state.params;
refreshParent();
navigation.goBack();
The only scenario where this does not work is on iOS. It works as long as I go to PersonScreen and refresh. However, if I go from PersonScreen to AppointmentScreen and back it does trigger the refreshParent (which is essentially _onRefresh), but then any attempts to pull down to trigger the RefreshControls onRefresh function fails. I've also added some console.log in the _onRefresh, but it doesn't even output anything.
If my AppointmentScreen instead looks like this:
const { refreshParent } = navigation.state.params;
//refreshParent();
navigation.goBack();
Everything works. So I'm experiencing that somehow calling refreshParent and then going back makes the following _onRefresh from the RefreshControl in PersonScreen not work.
Does anyone have any ideas why this is the case? As mentioned, I only experience this on iOS, but consistently so on iOS simulator and devices.
Can you create an expo version?
also, your refreshing is refreshing={refreshing} it should be refreshing={this.state.refreshing}

differents buttons, differents images? react native

I'm a student and I developing a mobile app with React Native.
My target is this image:
(https://cdn.discordapp.com/attachments/403580119714889736/407172407049060352/Apercu_bingo_2_choisir_invites.jpg)
I could write the code with independent buttons, the problem appears when I want to add different images to each button. (I'm waiting for the back dev to create a boucle to add all the images with the shortest code possible (looking forward for some loop ideas ;) ).
import React, {Component} from 'react';
import Button from 'react-native-button';
import
{
AppRegistry,
StyleSheet,
View,
Text,
TouchableHighlight,
Alert,
Image,
ScrollView,
TouchableWithoutFeedback
}
from 'react-native';
import styles from './Styles';
class ToggleButton extends React.Component {
render() {
return (
<View style={styles.cont2}>
<TouchableHighlight style={styles.bubblechoice} onPress={this.props.onPress}>
<View style={[styles.overlay, this.props.selected ? {backgroundColor: '#3C1088'} : {}]}>
<Image style={styles.bubblechoice} source={require('./photo1.jpg')}/>
</View>
</TouchableHighlight>
</View>
);
}
}
export default class MyComponent extends Component
{
constructor(props) {
super(props);
this.state = {
inv1: false,
inv2: false,
};
}
updateChoice(type) {
let newState = {...this.state};
newState[type] = !newState[type];
this.setState(newState);
}
render() {
return (
<View style={styles.containerinvite}>
<ScrollView contentContainerStyle={styles.list}>
<ToggleButton label='inv1' onPress={() => { this.updateChoice('inv1') } } selected={this.state.inv1}/>
<ToggleButton label='inv2' onPress={() => { this.updateChoice('inv2') } } selected={this.state.inv2}/>
<TouchableWithoutFeedback
onPress={() => {Alert.alert('OK');}}>
<View style={styles.button}>
<Text style={styles.buttonText}>ok</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
onPress1 = () => {
this.setState({
inv1: !this.state.inv1
});
}
onPress2 = () => {
this.setState({
inv2: !this.state.inv2
});
}
}
The result that I have is:
https://scontent-cdt1-1.xx.fbcdn.net/v/t35.0-12/28580783_10216099091730046_1132055272_o.png?oh=fdb33bbe2b82f29cac1d80b8e25f269e&oe=5A9B2488&dl=1, https://www.facebook.com/
The thing is that the View that changes the status color can't be without children, so I can't just change the image from there. I tried different options but I'm still can manage different photos with independents buttons.
From your parent component you should pass your photos to the child component and use that prop for your source instead of
<Image style={styles.bubblechoice} source={require('./photo1.jpg')}/> =>> This is wrong.
<Image style={styles.bubblechoice} source={require(photoUrls)}/> =>> It should be like this.
If you have further questions about it do not hesitate to ask.

E2E: Select an image from a UIImagePickerController with Wix Detox

Description
I need to write an e2e test that in some point it has to select an image in UIImagePickerController, I tried to use element(by.type('UIImagePickerController')). tapAtPoint() with no use. I need a way to select an image. I have found a way to do it with native tests.
Also mocking isn't an option for me since I use a higher version that the one react-native-repackeger needs.
Steps to Reproduce
Use with any application that uses image picker
Try to use element(by.type('UIImagePickerController')).tapAtPoint({ x: 50, y: 200 })
Detox, Node, Device, Xcode and macOS Versions
Detox: 6.0.2
Node: 8.9.0
Device: iOS Simulator 6s
Xcode: 9.2
macOS: 10.13.1
React-Native: 0.46.4
Device and verbose Detox logs
There's no logs, the device taps on the right location but the tap doesn't make an effect.
Noticed the original question stated that mocks were not an option in the case presented, but I came across this Stack Overflow question a few times in my searches for a solution and thought to share what I ultimately came up with for my situation.
I was able to get around the limitations for the e2e test by wrapping react-native-image-picker in my own export:
ImagePicker.js
import ImagePicker from 'react-native-image-picker';
export default ImagePicker;
And then creating a mock with a custom extension (i.e. e2e.js):
ImagePicker.e2e.js
const mockImageData = '/9j/4AAQSkZ...MORE BASE64 DATA OF CUTE KITTENS HERE.../9k=';
export default {
showImagePicker: function showImagePicker(options, callback) {
if (typeof options === 'function') {
callback = options;
}
callback({
data: mockImageData,
});
},
};
Finally, configure the metro bundler to prioritize your custom extension:
[project root]/rn-cli.config.js
const defaultSourceExts = require('metro-config/src/defaults/defaults')
.sourceExts;
module.exports = {
resolver: {
sourceExts: process.env.RN_SRC_EXT
? process.env.RN_SRC_EXT.split(',').concat(defaultSourceExts)
: defaultSourceExts,
},
};
Then run with the RN_SRC_EXT environment variable set to the custom extension:
RN_SRC_EXT=e2e.js react-native start
See the Detox Mocking Guide for more information.
Not sure if this is related, but for iOS 11 I can't even see those native view types in the Debug View Hierarchy.
For iOS 9 and 10 however, I would solve the problem like this:
it('select first image from camera roll', async () => {
// select a photo
await element(by.id('select_photo')).tap();
// Choose from Library...
await element(by.traits(['button']).and(by.type('_UIAlertControllerActionView'))).atIndex(1).tap();
// select Cemara Roll, use index 0 for Moments
await element(by.type('UITableViewCellContentView')).atIndex(1).tap();
// select first image
await element(by.type('PUPhotoView')).atIndex(0).tap();
});
There are probably many other possibilities to solve this problem with different native view types and accessibility traits.
I just used the example provided from react-native-image-picker to test with above code:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PixelRatio,
TouchableOpacity,
Image,
} from 'react-native';
import ImagePicker from 'react-native-image-picker';
export default class App extends React.Component {
state = {
avatarSource: null,
videoSource: null
};
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true
}
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
let source = { uri: response.uri };
// You can also display the image using data:
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
avatarSource: source
});
}
});
}
selectVideoTapped() {
const options = {
title: 'Video Picker',
takePhotoButtonTitle: 'Take Video...',
mediaType: 'video',
videoQuality: 'medium'
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled video picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
this.setState({
videoSource: response.uri
});
}
});
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity testID="select_photo" onPress={this.selectPhotoTapped.bind(this)}>
<View style={[styles.avatar, styles.avatarContainer, {marginBottom: 20}]}>
{ this.state.avatarSource === null ? <Text>Select a Photo</Text> :
<Image style={styles.avatar} source={this.state.avatarSource} />
}
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this.selectVideoTapped.bind(this)}>
<View style={[styles.avatar, styles.avatarContainer]}>
<Text>Select a Video</Text>
</View>
</TouchableOpacity>
{ this.state.videoSource &&
<Text style={{margin: 8, textAlign: 'center'}}>{this.state.videoSource}</Text>
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
avatarContainer: {
borderColor: '#9B9B9B',
borderWidth: 1 / PixelRatio.get(),
justifyContent: 'center',
alignItems: 'center'
},
avatar: {
borderRadius: 75,
width: 150,
height: 150
}
});
AppRegistry.registerComponent('example', () => App);

Open Webview on TouchableOpacity onPress React-Native

Presently I am using Linking but it is opening the url outside the app, I want this app to be opened within the app without showing the URL.
But unable to open Webview on TouchableOpecity onPress event in React-Native. Do I need to add a page and then open the page with URL ?
Can anyone please help.
I am considering the simplest of cases where i am rendering a single component and no navigator is being used.
class ABC extends Component {
constructor(props){
super(props)
this.state = {
check : false
}
}
renderWebView(){
if(this.state.check){
return(
<WebView
source={{uri: 'your url goes here'}}
style={{marginTop: 20}}
/>
);
}else {
return(
<TouchableOpacity
onPress={()=>this.setState({check: true})}>
<Text>Open WebView</Text>
</TouchableOpacity>
);
}
}
render() {
return (
<View style={{flex:1}}>
{this.renderWebView()}
</View>
);
}
}
You can use one of the Navigators and treat the webview component as one route.

How to implement slider menu in react Native

I'm new to react.
I need to develop slider menu in React-native.
I follow below link but that is not I want
http://www.reactnative.com/a-slide-menu-inspired-from-android-for-react-native/
Actually I need image which I attached here.
Please help me..
This react native package is pretty extensive, and really nice to use:
https://github.com/root-two/react-native-drawer
This is just a snippet of my code, you could create a menu bar with a button that calls the openDrawer method, and using this drawer you can set the animation to be however you like, and include a scrollview inside the drawer itself. Hope this helps!
var React = require('react-native');
var {
StyleSheet,
Component,
View,
Text,
Navigator,
TouchableHighlight,
TouchableOpacity,
} = React;
var styles = require('./styles');
var Drawer = require('react-native-drawer')
var drawerStyles = {
drawer: {
shadowColor: "#000000",
shadowOpacity: 0.8,
shadowRadius: 0,
}
}
var MainPage = React.createClass({
getInitialState: function(){
return {
drawerType: 'overlay',
openDrawerOffset:.3,
closedDrawerOffset:0,
panOpenMask: .1,
panCloseMask: .9,
relativeDrag: false,
panStartCompensation: true,
openDrawerThreshold: .25,
tweenHandlerOn: false,
tweenDuration: 550,
tweenEasing: 'easeInOutQuad',
disabled: false,
tweenHandlerPreset: null,
acceptDoubleTap: true,
acceptTap: true,
acceptPan: true,
rightSide: false,
showView: true,
}
},
setDrawerType: function(type){
this.setState({
drawerType: type
});
},
openDrawer: function(){
this.refs.drawer.open();
},
closeDrawer: function(){
this.refs.drawer.close();
},
setStateFrag: function(frag){
this.setState(frag);
},
render: function() {
var menu = <Menu
closeDrawer={this.closeDrawer}
navigator={this.props.navigator} />;
return (
<Drawer
ref="drawer"
onClose={this.onClose}
type={this.state.drawerType}
animation={this.state.animation}
openDrawerOffset={this.state.openDrawerOffset}
closedDrawerOffset={this.state.closedDrawerOffset}
panOpenMask={this.state.panOpenMask}
panCloseMask={this.state.panCloseMask}
relativeDrag={this.state.relativeDrag}
panStartCompensation={this.state.panStartCompensation}
openDrawerThreshold={this.state.openDrawerThreshold}
content={**YOURCUSTOMENU**}
styles={drawerStyles}
disabled={this.state.disabled}
tweenHandler={this.tweenHandler}
tweenDuration={this.state.tweenDuration}
tweenEasing={this.state.tweenEasing}
acceptDoubleTap={this.state.acceptDoubleTap}
acceptTap={this.state.acceptTap}
acceptPan={this.state.acceptPan}
changeVal={this.state.changeVal}
negotiatePan={false}
side={this.state.rightSide ? 'right' : 'left'}
>
<View>
<**YOURTOOLBAR** onPress={this.openDrawer}/>
<**YOURCONTENT_VIEW**/>
</View>
</Drawer>
);
},
});
module.exports = MainPage;
I've added an example that implements react-native-router-flux component to react-native-drawer. In this way it presents an easy scaffolding as cross-platform.
From what I understand, you want to toogle the slider menu with the hamburger button.
Although react-native-navigation-drawer
That can be achieved with the toogleSlideMenu function of the SliderMenu.
A simple example might be:
import React, {
View,
Text,
ScrollView,
} from 'react-native';
import SlideMenu from 'react-native-navigation-drawer';
var BasicExample = React.createClass({
render() {
return (
<View style={styles.container}>
<View>
<Text onPress={() => this._slideMenu.toogleSlideMenu()}> Your status bar </Text>
</View>
<SlideMenu
ref={(c) => this._slideMenu = c}
menu={<Menu />}
>
<View>
<Text>Your content</Text>
</View>
</SlideMenu>
</View>
);
}
});
var Menu = React.createClass({
render() {
return (
<View style={styles.container}>
<ScrollView
contentContainerStyle={styles.contentContainer}
style={styles.scrollView}>
<Text>Gallery</Text>
<Text>Latest</Text>
<Text>Events</Text>
<Text>Update</Text>
</ScrollView>
</View>
);
}
});
You can check this complete sidemenu project on github. This project contains ToolbarAndroid, routes, DrawerLayoutAndroid, overflow menu and other components.
https://github.com/darde/react-native-sidemenu

Resources