React Native : Arranging elements - react-native

I am building a very simple app with a picker and two inputs/labels.
It currently looks like this in my iphone.
This is my code
import React from 'react';
import { StyleSheet, Text, View, Button, Modal, TextInput, Picker } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
}
state = {
b1text: 'Kg',
b2text: 'Cm',
weight: '',
height: '',
standard: 'Metric'
}
render() {
return (
<View style={styles.container}>
<Picker
selectedValue={this.state.standard}
onValueChange={(itemValue, itemIndex) => {
this.setState({standard: itemValue});
if(itemValue === "Metric") {
this.setState({b1text: "Kg"});
this.setState({b2text: "Cm"});
}
if(itemValue === "Imperial") {
this.setState({b1text: "Lbs"});
this.setState({b2text: "Inches"});
}
} }
style={{height: 100, width: 100 }}
>
<Picker.Item label="Metric" value="Metric" />
<Picker.Item label="Imperial" value="Imperial" />
</Picker>
<TextInput
style={{height: 40, width: 60, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text: weight})}
value={this.state.weight}
/>
<Text>{this.state.b1text}</Text>
<TextInput
style={{height: 40, width: 60, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text: height})}
value={this.state.height}
/>
<Text>{this.state.b2text}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
});
But I want it to look something like this as shown below.
I have tried margin, padding etc. Still no luck.
Can someone tell me what css/flex property I can use to change the UI like how I want ?

I've created an Expo Snack that has a closer example of the UI you want to achieve. But I'll leave it to you to work out the details.
import React from 'react';
import { StyleSheet, Text, View, TextInput, Picker } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
}
state = {
b1text: 'Kg',
b2text: 'Cm',
weight: '',
height: '',
standard: 'Metric',
};
render() {
return (
<View style={styles.container}>
<View style={styles.top}>
<Picker
selectedValue={this.state.standard}
onValueChange={itemValue => {
this.setState({ standard: itemValue });
if (itemValue === 'Metric') {
this.setState({ b1text: 'Kg' });
this.setState({ b2text: 'Cm' });
}
if (itemValue === 'Imperial') {
this.setState({ b1text: 'Lbs' });
this.setState({ b2text: 'Inches' });
}
}}>
<Picker.Item label="Metric" value="Metric" />
<Picker.Item label="Imperial" value="Imperial" />
</Picker>
</View>
<View style={styles.bottom}>
<TextInput
style={{
height: 40,
width: 60,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={() => this.setState({ text: weight })}
value={this.state.weight}
/>
<Text>{this.state.b1text}</Text>
<TextInput
style={{
height: 40,
width: 60,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={() => this.setState({ text: height })}
value={this.state.height}
/>
<Text>{this.state.b2text}</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
top: {
width: '100%',
flex: 1,
},
bottom: {
flex: 1,
alignItems: 'center',
},
});
One of the crucial things you need to is learn how to write styles with react-native. Here is a resource that has a guide of all of the style properties you can use with const {StyleSheet} from 'react-native'.
https://github.com/vhpoet/react-native-styling-cheat-sheet
Good luck :)

Related

How can I use react-native-picker to display content on the page depending on the current value of the picker?

I am trying to use react-native-picker in my project and recently came across this Expo Snack: https://snack.expo.dev/HkM_BcGBW
I want to display content on the page depending on the current value of the picker. For instance, some text right below the picker saying "The option you have selected is [text of the currently-selected option in the picker]." How can I do this?
You can do as the example and use state value to display in the component
import React, { Component } from 'react';
import { Text, View, StyleSheet, Picker } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
language: 'java',
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Unstyled:</Text>
<Picker
style={styles.picker} itemStyle={styles.pickerItem}
selectedValue={this.state.language}
onValueChange={(itemValue) => this.setState({language: itemValue})}
>
<Picker.Item label="Java" value="java" />
<Picker.Item label="JavaScript" value="js" />
<Picker.Item label="Python" value="python" />
<Picker.Item label="Haxe" value="haxe" />
</Picker>
<Text>The option you have selected is {this.state.language}</Text>
</View>
);
}
}
But do remember
onValueChange={(itemValue) => this.setState({language: itemValue})}
this stores value rather than the label.
you can use conditional rendering as below:
import React, { Component } from 'react';
import { Text, View, StyleSheet, Picker } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
language: 'haxe',
firstLanguage: 'java',
secondLanguage: 'js',
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>{this.state.language}</Text>
<Picker
style={styles.picker} itemStyle={styles.pickerItem}
selectedValue={this.state.language}
onValueChange={(text) => this.setState({language: text})}
>
<Picker.Item label="Java" value="java" />
<Picker.Item label="JavaScript" value="js" />
<Picker.Item label="Python" value="python" />
<Picker.Item label="Haxe" value="haxe" />
</Picker>
{this.state.language == "haxe"?
<Text>Hello Haxa</Text>
:this.state.language == "js"?
<Text>Helo JavaScript</Text>
:this.state.language == "python"?
<Text>Helo Python</Text>
:this.state.language == "java"?
<Text>Helo Java</Text>
:<Text>Nothing</Text>}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
padding: 20,
backgroundColor: 'white',
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginTop: 20,
marginBottom: 10,
},
picker: {
width: 200,
backgroundColor: '#FFF0E0',
borderColor: 'black',
borderWidth: 1,
},
pickerItem: {
color: 'red'
},
onePicker: {
width: 200,
height: 44,
backgroundColor: '#FFF0E0',
borderColor: 'black',
borderWidth: 1,
},
onePickerItem: {
height: 44,
color: 'red'
},
twoPickers: {
width: 200,
height: 88,
backgroundColor: '#FFF0E0',
borderColor: 'black',
borderWidth: 1,
},
twoPickerItems: {
height: 88,
color: 'red'
},
});

React native search onChange input text, code structure

I am building a searchBar, whenever I do search I get undefined error because the value doesn't exist in state till I finish the whole value so I know that I will get error yet I am unable to solve it so I am trying to render cards according to the search input I think I did hard code my homeScreen I am not sure if I am doing it even right and here it comes the question to the three if statements inside render that I have is it good practice ? is it professional ? can i do something else which makes code easier to read and shorter ? I was thinking of eliminating the third if but I wasn't able to change state inside the second if so I had to add the toggle search function to let it work any ideas on how to eliminate the third if would be nice ..! thank you in advance guys
homeScreen.js
import axios from 'axios';
import React from 'react';
import {
ActivityIndicator,
ScrollView,
Text,
View,
TouchableOpacity,
TextInput,
} from 'react-native';
import Card from '../Components/Card/card';
export default class HomeScreen extends React.Component {
state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
componentDidMount() {
this.getData();
}
toggleSearch = () => {
console.log('hlelleloe');
this.setState({
search: true,
});
};
getData = () => {
const requestUrls = Array.from({length: 9}).map(
(_, idx) => `http://api.tvmaze.com/shows/${idx + 1}`,
);
const handleResponse = data => {
this.setState({
isLoading: false,
shows: data,
});
};
const handleError = error => {
console.log(error);
this.setState({
isLoading: false,
});
};
Promise.all(requestUrls.map(url => axios.get(url)))
.then(handleResponse)
.catch(handleError);
};
render() {
const {isLoading, shows, search, title} = this.state;
if (isLoading) {
return <ActivityIndicator size="large" color="#0000ff" />;
} else if (!search) {
return (
<View>
<View>
<TouchableOpacity
onPress={this.toggleSearch}
style={{height: 300, width: 300}}>
<Text style={{textAlign: 'center', fontSize: 40}}>
Press to Search
</Text>
</TouchableOpacity>
</View>
<ScrollView style={{backgroundColor: '#E1E8E7'}}>
{shows.length &&
shows.map((show, index) => {
return (
<Card
key={show.data.id}
title={show.data.name}
rating={show.data.rating.average}
source={show.data.image.medium}
genres={show.data.genres}
language={show.data.language}
network={show.data.network}
schedule={show.data.schedule}
summary={show.data.summary}
navigation={this.props.navigation}
/>
);
})}
</ScrollView>
</View>
);
} else if (search) {
console.log(title);
return (
<View>
<TextInput
style={{
height: 100,
width: 100,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={searchedTitle => (
<Card title={shows.data.searchedTitle} />
)}
/>
</View>
);
}
}
}
Card.js
import React from 'react';
import {
Image,
View,
Text,
Button,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import Icon from 'react-native-vector-icons/FontAwesome';
const Card = props => {
return (
<View style={styles.container}>
<Image style={styles.Image} source={{uri: `${props.source}`}} />
<Text style={styles.title}>{props.title}</Text>
<View style={styles.ratingContainer}>
<Text style={styles.rating}>Rating: {props.rating}</Text>
<Icon name="star" size={30} color="grey" />
</View>
<TouchableOpacity
style={styles.button}
onPress={() => {
props.navigation.navigate('Details', {
title: props.title,
rating: props.rating,
source: props.source,
genres: props.genres,
language: props.language,
network: props.network,
schedule: props.schedule,
summary: props.summary,
});
}}>
<Text style={styles.buttonText}>Press for details </Text>
</TouchableOpacity>
</View>
);
};
export default Card;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
Image: {
flex: -1,
width: wp('90%'),
height: hp('65%'),
},
title: {
flex: 1,
fontSize: 40,
borderRadius: 10,
color: '#3C948B',
margin: 15,
justifyContent: 'center',
alignItems: 'center',
},
ratingContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'white',
elevation: 6,
justifyContent: 'space-between',
borderWidth: 1,
width: 300,
},
rating: {
fontSize: 25,
paddingLeft: 15,
},
button: {
flex: 1,
color: '#3C948B',
backgroundColor: '#3C948B',
height: hp('7%'),
width: wp('70%'),
margin: 20,
alignItems: 'center',
borderBottomLeftRadius: 10,
borderTopRightRadius: 10,
},
buttonText: {
flex: 1,
fontSize: 25,
},
});
you Need to implement a constructor for your React component.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state
Binding event handler methods to an instance
Do
state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
replace this with
constructor(props){
super(props);
this.state = {
shows: [],
isLoading: true,
search: false,
title: '',
};
}

Conditional rendering in react native using map function

I am trying to build a notification page where notifications are being fetched from a remote server using the Notification function, so I initially set the notificationLoaded to false in order to use an ActivityLoader before rendering the notification to the page.
But I am confused about how I can render an ActivityLoader before the notificationLoaded state is set to true.
Thanks in advance
import React, { Component } from 'react';
import {
StyleSheet,
ScrollView,
Dimensions,
Text,
ActivityIndicator,
TouchableOpacity,
TextInput,
View,
StatusBar,
ImageBackground,
KeyboardAvoidingView,
AsyncStorage,
} from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { Font } from 'expo';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { KeyboardAwareView } from 'react-native-keyboard-aware-view';
const { height, width } = Dimensions.get('window');
export default class Notification extends Component {
constructor(props) {
super(props);
this.state = {
notification: [],
notificationLoaded: false,
};
}
Notification = () => fetch('http://texotrack.com/api/user/notification.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'fetch',
}),
}).then(response => response.json()).then((responseJsonFromServer) => {
console.log(responseJsonFromServer);
this.setState({
notification: responseJsonFromServer,
notificationLoaded: true,
});
})
componentDidMount() {
this.Notification();
AsyncStorage.getItem('key').then((data) => {
const val = JSON.parse(data);
this.setState({
username: data.name,
photo: data.photo,
email: data.email,
userId: data.id,
address: data.address,
});
});
}
render() {
const notificationList = this.state.notification.map(data => (
<View key={data.msg_id} style={styles.notification}>
<View style={{
display: 'flex', flexDirection: 'row',
}}
>
<Text style={{ color: 'green' }}><Ionicons size={20} color="green" name="ios-notifications" /></Text>
<Text style={{
color: '#c9c9c9', fontSize: 15, fontWeight: 'bold', marginLeft: 5,
}}
>
{data.date_sent}
</Text>
</View>
<View style={styles.notificationBody}>
<Text style={{ color: '#000', fontSize: 16 }}>{data.message}</Text>
</View>
<View style={styles.lineStyle} />
</View>
));
return (
<View style={styles.container}>
<StatusBar
style={{ height: 30 }}
backgroundColor="black"
/>
<View elevation={5} style={styles.headers}>
<Text style={{
fontSize: 25, color: 'green', textTransform: 'uppercase', fontWeight: 'bold',
}}
>
Notification
</Text>
<Text style={styles.topIcon} onPress={this.GoHome}>
<Ionicons name="md-home" size={25} color="black" />
</Text>
</View>
<View style={{ flex: 1, margin: 5 }}>
<ScrollView alwaysBounceVertical contentContainerStyle={{ flexGrow: 1 }} enabled bounces>
{notificationList}
</ScrollView>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
lineStyle: {
borderWidth: 0.3,
borderColor: '#c9c9c9',
margin: 10,
},
headers: {
height: 50,
marginBottom: 10,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
textAlignVertical: 'center',
padding: 10,
shadowColor: '#444',
shadowOffset: {
width: 0,
height: 60,
},
shadowRadius: 5,
shadowOpacity: 1.0,
backgroundColor: '#fff',
},
topIcon: {
marginTop: 3,
fontWeight: 'bold',
},
content: {
margin: 10,
flex: 1,
},
notification: {
height: 70,
padding: 10,
},
});
This is what you call conditional rendering. This can be achieved simply by using if conditions in your render function like:
render(){
// if loading true render Loader
if (this.state.notificationStateLoaded === true) {
return(
<ActivityLoader>
)
} else { // when loading false render the other component
return(
<WhateverComponentWhenDataHasArrived/>
)
}
}
React's documentation is pretty cool. Check this official link for conditional rendering
https://reactjs.org/docs/conditional-rendering.html
I dont understand what you need to do in your map function but to do a conditional rendering inside your render you can do :
<View>
{someCondition&& <Text>Hello</Text>}
</View>
else
<View>
{someCondition? <Text>Condition True</Text> : <Text>Condition false</Text>}
</View>

onChange text is not updating its state

import React, { Component } from 'react';
import { Text, View, TextInput, Button, Alert } from 'react-native';
import datum from './data';
export default class Signup extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'sff', number: '' };
}
signupPressed = () => {
const { name } = this.state;
console.log('checkss', name);
};
render() {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-evenly',
alignItems: 'center',
}}>
<TextInput
style={{
height: 40,
borderColor: 'gray',
borderWidth: 1,
width: '50%',
}}
onChangeText={TextInputValue => this.setState({ name })}
placeholder="Name"
/>
<TextInput
style={{
height: 40,
borderColor: 'gray',
borderWidth: 1,
width: '50%',
}}
onChangeText={text => this.setState({ name })}
placeholder="Mobile no"
/>
<Button
onPress={this.signupPressed}
title="Signup"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
}
I have Text input but the onChangeText props is not working as it is
Expected behavior
Has to log the updated name value from the state when the button is clicked
Reality
when I click the button it logs me "checkss" only, not the name value
What is strange here!!
when I click the button for the first time it logs me "checkss,sff" but, when I click it for the second time it shows checkss only
That's because in onChangeText you'll need to do this,
onChangeText={value=>{this.setState({stateVariable:value})}};
<TextInput
value={this.state.name}
style={{height: 40, borderColor: 'gray', borderWidth: 1,width:'50%'}}
onChangeText={(name) => this.setState({name})}
placeholder="Name"
/>
Try above code it will work for you
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1,width:'50%'}}
onChangeText={(text) => this.setState({name: text })}
placeholder="Name"
/>
Your code fails because you made a mistake when you declare de arrow function
onChangeText={TextInputValue => this.setState({name})}
It must be
onChangeText={TextInputValue => this.setState({ name: TextInputValue })}
Using Ecma6 can be simplified as
onChangeText={name => this.setState({ name })}
To avoid performance issues it is recommended not to use an inline function because is instantiated in all the render cycles. Is better if you create a class method and use it by reference.
export default class Signup extends React.Component {
constructor(props) {
super(props)
this.state = {name:"sff",number:""};
this.handleChange = this.handleChange.bind(this);
}
handleChange(name) {
this.setState({ name });
}
render() {
/* rest of code omitted */
<TextInput
style={
{ height: 40, borderColor: 'gray', borderWidth: 1,width:'50%' }
}
onChangeText={this.handleChange}
placeholder="Mobile no"
/>
/* rest of the code omitted */
}
}

Using react-native-camera, how to access saved pictures?

My goal is to use the react-native-camera and simply show a picture on the same screen, if a picture has been taken. I'm trying to save the picture source as "imageURI". If it exists, I want to show it, if a picture hasn't been taken yet, just show text saying No Image Yet. I've got the camera working, since I can trace the app is saving pictures to the disk. Having trouble with the following:
How to assign the capture functions data to a variable when I take the picture, that I can call later (imageURI).
Don't know how to do an if statement in Javascript to check if a variable exists yet.
import Camera from 'react-native-camera';
export default class camerahere extends Component {
_takePicture () {
this.camera.capture((err, data) => {
if (err) return;
imageURI = data;
});
}
render() {
if ( typeof imageURI == undefined) {
image = <Text> No Image Yet </Text>
} else {
image = <Image source={{uri: imageURI, isStatic:true}}
style={{width: 100, height: 100}} />
}
return (
<View style={styles.container}>
<Camera
captureTarget={Camera.constants.CaptureTarget.disk}
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}>
{button}
<TouchableHighlight onPress={this._takePicture.bind(this)}>
<View style={{height:50,width:50,backgroundColor:"pink"}}></View>
</TouchableHighlight>
</Camera>
I found the answer to my own question. This is an example of the react-native-camera being used.
https://github.com/spencercarli/react-native-snapchat-clone/blob/master/app/routes/Camera.js
Found this answer in another earlier posted question answered by #vinayr. Thanks!
Get recently clicked image from camera on image view in react-native
Here's the code from the first link:
import React, { Component } from 'react';
import {
View,
StyleSheet,
Dimensions,
TouchableHighlight,
Image,
Text,
} from 'react-native';
import Camera from 'react-native-camera';
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
height: Dimensions.get('window').height,
width: Dimensions.get('window').width
},
capture: {
width: 70,
height: 70,
borderRadius: 35,
borderWidth: 5,
borderColor: '#FFF',
marginBottom: 15,
},
cancel: {
position: 'absolute',
right: 20,
top: 20,
backgroundColor: 'transparent',
color: '#FFF',
fontWeight: '600',
fontSize: 17,
}
});
class CameraRoute extends Component {
constructor(props) {
super(props);
this.state = {
path: null,
};
}
takePicture() {
this.camera.capture()
.then((data) => {
console.log(data);
this.setState({ path: data.path })
})
.catch(err => console.error(err));
}
renderCamera() {
return (
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}
captureTarget={Camera.constants.CaptureTarget.disk}
>
<TouchableHighlight
style={styles.capture}
onPress={this.takePicture.bind(this)}
underlayColor="rgba(255, 255, 255, 0.5)"
>
<View />
</TouchableHighlight>
</Camera>
);
}
renderImage() {
return (
<View>
<Image
source={{ uri: this.state.path }}
style={styles.preview}
/>
<Text
style={styles.cancel}
onPress={() => this.setState({ path: null })}
>Cancel
</Text>
</View>
);
}
render() {
return (
<View style={styles.container}>
{this.state.path ? this.renderImage() : this.renderCamera()}
</View>
);
}
};
export default CameraRoute;