Presenting & Closing a modal - ios

So I have an Initial Screen below which allows you to click on a button and present a modal screen:
import SettingsScreen from './SettingsScreen';
...
export default class InitialScreen extends Component {
constructor(props) {
super(props);
this.state = {modalVisible: false};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View>
<NavigationBar
title={{ title: 'Initial Screen', tintColor: 'white', }}
leftButton={
<TouchableOpacity onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Image style={styles.leftButton} source={require('./../img/settings.png')} />
</TouchableOpacity>
}
rightButton={{ title: 'Forward', tintColor: 'white' }}
style={{ backgroundColor: '#2196F3', }}
statusBar={{ tintColor: '#1976D2', style: 'light-content' }}
/>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<SettingsScreen />
</Modal>
</View>
);
}
}
It works, but now in my Modal screen I have a button which allows you to dismiss the modal:
import ...
export default class ModalScreen extends Component {
render() {
return (
<View>
<TouchableOpacity onPress={() => {
this.props.setModalVisible(!this.state.modalVisible)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>
</View>
);
}
}
But it's giving me an error saying this.props.setModalVisible(!this.state.modalVisible) is not a function.
How would I dismiss the modal within the ModalScreen?
Thank you.

you should pass the setModalVisible() function to the modal component
Initial Component:
<ModalComponent closeModal={this.setModalVisible} />
and on ModalComponent call it like this:
<TouchableOpacity onPress={() => {
this.props.closeModal(false)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>

For custom functions in react native use ES6 style:
setModalVisible = (visible) => {
this.setState({modalVisible: visible});
}
And the code should be: this.setModalVisible(!this.state.modalVisible)

Related

FlatList item click is not rendering this

export default class HistoryScreen extends BaseScreen {
constructor(props){
super(props);
this.state = {
mainListData:[],
listData:[],
searchText:'',
};
}
listRowPressed(item) {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex:1, backgroundColor: '#FFF'}}>
<FlatList
data={this.state.listData}
renderItem={({item}) => <ListComp data={item} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = item => (
<TouchableOpacity onPress={() => this.listRowPressed(item)
}>
<View style={styles.row}>
</View>
</TouchableOpacity>
);
I am displaying data in FlatList, however clicking on item gives me this4. listRowPressed is undefined, I tried binding the function too but didn't work. What is wrong in the code?
You have to pass listRowPressed in your ListComp component. Your whole code should be like this :
export default class HistoryScreen extends BaseScreen {
constructor(props) {
super(props);
this.state = {
mainListData: [],
listData: [],
searchText: '',
};
}
listRowPressed = (item) => {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, backgroundColor: '#FFF' }}>
<FlatList
data={this.state.listData}
renderItem={({ item }) => <ListComp data={item} listRowPressed={this.listRowPressed} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = (props) => (
<TouchableOpacity
onPress={() => props.listRowPressed(props.item)}
>
<View style={styles.row}>
{/* Do whatever with props.item here */}
</View>
</TouchableOpacity>
);
Also note that I have converted your method listRowPressed simple function to arrow function.
Try this
<FlatList
data={this.state.listData}
renderItem={this.listComp}
keyExtractor={(item, index) => index.toString()}
/>
listComp = ({item}) => (
return(
<TouchableOpacity onPress={() => this.listRowPressed(item)} >
<View style={styles.row}>
</View>
</TouchableOpacity>
);
);

React-Native. TouchableOpacity works only when tap with 2 fingers

I'm running my app via React-Native and native-base and I got some problems with component TouchableOpacity.
When I'm writing my component like
<TouchableOpacity onPress={() => {this.onPress()}}>
<Text>Some text</Text>
</TouchableOpacity
It works perfect, when I tap with 1 finger
But when I'm running like this - My Code:
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
It is ignoring 1 tap, twice tap etc, it is only working when I tap with 2 fingers. Didn't find any info about this problem. May be some one know how to solve this?
Thanks
Added FullCode:
import React, { Component } from 'react';
import {
Container,
Button,
Header,
Left,
Icon,
Body,
Right,
Text,
Content,
List,
ListItem,
Thumbnail
} from 'native-base';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
export default class Restaurants extends Component {
constructor ( props ) {
super( props );
this.state = {
data: this.props.data
};
}
onPress () {
console.log( 'Hello' );
}
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
render () {
return (
<Container>
<Header style={styles.header}>
<Left>
<Button transparent>
<Icon style={styles.header_icon} name="arrow-back"/>
</Button>
</Left>
<Body>
<Text>Ресторанны</Text>
</Body>
<Right>
<Button transparent>
<Icon style={styles.header_icon} name="restaurant"/>
</Button>
</Right>
</Header>
<Content>
{this.renderList()}
</Content>
</Container>
);
}
}
const styles = StyleSheet.create( {
header: {
backgroundColor: '#606dff'
},
header_icon: {
color: 'black'
},
example: {
backgroundColor: 'red'
}
} );
As we spoken, I'll post it here so it's better to read and copy the code.
Try this:
renderList() {
return (
<List>
{
this.state.data.map( ( restaurant, index ) => {
return (
<ListItem>
<TouchableOpacity
onPress={() => {
this.onPress();
}}
key={index}
>
<View style={styles.example}>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</View>
</TouchableOpacity>
</ListItem>
);
});
}
</List>
);
}
I swapped <ListItem> and <TouchableOpacity>
There might be any conflict the way you wrote.
Let me know if it worked.

How did I use the push() function in NavigatorIOS?

I want to Push to a new Component by the function push() in NavigatorIOS. It's like following:
renderRow(rowData, sectionID, rowID) {
var imgSource = IMAGE_URLS[rowID];
return (
<TouchableHighlight onPress = {() => {
this.props.navigator.push({
title: 'test',
component: example,
});
}}>
<View>
<View style={styles.row}>
<Image
source={imgSource}
style={styles.thum}
/>
<Text style={styles.text}>
{rowData}
</Text>
</View>
</View>
</TouchableHighlight>
);
}
But it will get a error when I click the TouchableHighlight.
I refered these two questions(1 and 2) before this. And the complete code is in this link
this is not binded to the class inside of renderRow().
You have to bind this either in the constructor:
this.renderRow = this.renderRow.bind(this);
or inside the render method:
render() {
var navStatusBarConfig = {
style: 'light-content',
}
return (
<View style={{ flex: 1, backgroundColor: '#F5FCFF'}}>
<View styles={styles.nav}></View>
<ListView
automaticallyAdjustContentInsets={false}
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
pageSize={4}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
As to why, here is the reason :
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
And a more complete blog about how to bind this [there are many, blogs and ways to bind this]) :
http://blog.andrewray.me/react-es6-autobinding-and-createclass/

Content hidden behind TabBarIOS with React Native

I'm building an iOS app with React Native and am implementing a TabBarIOS. The content on the tabs seems to flow behind and be obscured by the bar. In xcode I would have just unchecked the "extend edges" boxes but am not sure how to do this with React Native.
Here's an abbreviated version of what I'm trying to do. The <View> from CreateUser flows behind the tab bar. Is there an easy way to make sure content doesn't get obscured by the tab bar?
import React from 'react'
import {
StyleSheet,
Text,
TextInput,
View,
TouchableHighlight,
} from 'react-native'
export default class TabBar extends React.Component {
state = {
selectedTab: 'list'
}
render() {
return (
<TabBarIOS selectedTab={this.state.selectedTab}
unselectedTintColor="#ffffff"
tintColor="#ffe429"
barTintColor="#294163">
<TabBarIOS.Item
title="My List"
systemIcon="bookmarks"
selected={this.state.selectedTab==='list'}
onPress={() => {
this.setState({
selectedTab: 'list',
});
}}
>
<CreateUser />
</TabBarIOS.Item>
</TabBarIOS>
);
}
}
var styles = StyleSheet.create({
tabContent: {
flex: 1,
alignItems: 'center',
},
tabText: {
color: 'darkslategrey',
margin: 50,
},
});
export default class CreateUser extends React.Component{
render(){
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button}>
<Text style={styles.buttonText}>LOG IN</Text>
</TouchableHighlight>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "flex-end",
alignItems: 'center',
},
button: {
backgroundColor: "#ffe429",
borderRadius: 3,
height: 60,
width: 200,
margin: 7,
//flex: 1,
alignItems: "center",
justifyContent: "center",
},
buttonText: {
color: "#294163",
}
})
This was a problem for me when using a NavigatorIOS component that then rendered it's initialRoute component which contained a TabBarIOS component.
If this is the case for your scenario, you can fix it by using a ScrollView:
Add the flex layout style to your NavigatorIOS:
<NavigatorIOS
initialRoute={{
component: MyView,
title: 'My View',
}}
style={{flex: 1}}
/>
Use a ScrollView:
<TabBarIOS>
<TabBarIOS.Item
systemIcon="history"
title="A Tab">
<ScrollView>
<Text>
Hello World
</Text>
</ScrollView>
</TabBarIOS.Item>
</TabBarIOS>
In my case I needed to add flex: 1 to the style props for the top-level View of the screen.
RN Navigation docs
//MyScreen.tsx
export default () => (
<View style={{ flex: 1 }}>
...
</View>
)

React Native with Redux- Problems updating state correctly

I'm trying to upload images that I've base64 encoded but it doesn't seem to save the state to the app so I can upload the images to my server. The state only seems to save within the function and not to the entire component. Any suggestions as to what I'm doing wrong?
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.state = {
selected: image
};
console.log(this.state)
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity style={ styles.button } onPress={ this._addImage.bind( this ) }>
<Text>Add Image</Text>
</TouchableOpacity>
<TouchableOpacity style={ styles.button } onPress={this._uploadImage} >
<Text>Upload Image</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.container}>
<View style={styles.imageGrid}>
{ this.state.images.map((image) => {
return (
<TouchableHighlight onPress={this._selectImage.bind(null, image.uri)}>
<Image key={ _generateUUID() } style={styles.image} source={{ uri: image.uri }} />
</TouchableHighlight>
);
})
}
</View>
</ScrollView>
</View>
);
}
};
First, this-bind your _selectImage-method in constructor. Then use "setState" instead of this.state = {...}
You need only once to create the state object, best in constructor. Use then setState instead for further modifications.
constructor(props) {
super(props);
this.state = {selected: null};
this._selectImage = this._selectImage.bind(this);
}
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.setState({
selected: image
});
console.log(this.state)
});
}

Resources