Implementing a feedback screen in React Native - react-native

project output design
Installing Dependencies:-
we need one package called https://github.com/jeanregisser/react-native-slider
Coding :-
Finally, let’s get to what really matters. So… The logic is simple. We will use te Slider to get some value from the user. Since we have 5 possibilities, the values of the Slider will range from 0 to 4. To each value we will assign a label, color and emoji.
const colors = ['#F5CECE', '#FFE3D5', '#FFF5D1', '#F0FAEA', '#D4E9C6'];
const labels = ['Horrible', 'Not Good', 'OK!', 'Good', 'Excellent'];
const faces = [crying, sad, straight, laughing, smiling];
I did it using arrays, that seemed the simpliest solution to me. So, when the user give us a value through the Slider, what we have to do is to get the value of the array in the correspondent position.
In order to these things work properly, we have to set up the slider. The component is really easy to use and understand.
So… I set the minimum and maximum value. The step is how much the slider should increase or decrease. Since we don’t want values like 4.5. I defined it to be 1. The rest of the props are used to style.
import { StyleSheet, Text, View, Image, TouchableOpacity, Dimensions, TextInput, ScrollView } from 'react-native'
import React, { useEffect, useState } from "react";
import Slider from 'react-native-slider'
const FeedbackScreen = ({feedbackModalProp, feedbackPayload}) => {
const [rating, setRating] = useState(3)
const [fedDesc, setFedDesc] = useState()
const colors = ['#F5CECE', '#FFE3D5', '#FFF5D1', '#F0FAEA', '#D4E9C6'];
const labels = ['Horrible', 'Not Good', 'OK!', 'Good', 'Excellent!'];
// const faces = [crying, sad, straight, laughing, smiling];
//import your emojis
const faces = [require('../../assets/images/feedbackEmojies/crying.png'), require('../../assets/images/feedbackEmojies/sad.png'), require('../../assets/images/feedbackEmojies/straight.png'), require('../../assets/images/feedbackEmojies/laughing.png'), require('../../assets/images/feedbackEmojies/smiling.png')];
return (
<>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={{
...styles.container,
backgroundColor: colors[rating],
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
paddingBottom: 55,
}}>
<Text style={styles.title}>Rate Your Experience</Text>
<Image
style={styles.smiley}
source={faces[rating]}
// source={require('../../assets/images/feedbackEmojies/straight.png')}
/>
<Text style={styles.ratLabel}>{labels[rating]}</Text>
<Slider
style={styles.slider}
value={rating}
onValueChange={value => setRating(value)}
minimumValue={0}
maximumValue={4}
step={1}
thumbTintColor={colors[rating]}
thumbStyle={styles.sliderThumb}
minimumTrackTintColor="#666"
maximumTrackTintColor="#666" />
<View style={{ marginVertical: 10 , marginTop: 14}}>
<Text style={styles.headerLabel}>Tell us what can be Improved?</Text>
<TextInput
multiple={true}
placeholder={'Tell us on how can we improve....'}
style={[styles.textinput, {
// color: "#000",
paddingLeft: 5,
marginTop: 5,
borderWidth: 1,
width: Dimensions.get('window').width / 1 - 20,
height: 150,
borderRadius: 5,
borderColor: '#ccc',
textAlignVertical: 'top',
}]}
onChangeText={(text) => setFedDesc(text)}
numberOfLines={4}
/>
</View>
</View>
</ScrollView>
<TouchableOpacity onPress={() => onFeedbackSubmit()} style={styles.buttonContainer}>
<Text style={styles.buttonLabel}>Submit</Text>
</TouchableOpacity>
</>
)
}
export default FeedbackScreen
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
title: {
// fontWeight: 'bold',
marginVertical: 10,
fontFamily: 'Roboto-BoldItalic',
letterSpacing: 2.5,
color: '#000',
fontSize: 26
},
smiley: {
width: 200,
height: 200,
margin: 40
},
ratLabel: {
fontFamily: 'Roboto-MediumItalic',
fontWeight: 'bold',
fontSize: 22,
color: '#fe786a',
},
slider: {
width: '80%'
},
sliderThumb: {
borderRadius: 5,
borderWidth: 1,
borderColor: '#666'
},
buttonContainer: {
position: 'absolute',
width: '100%',
padding: 15,
bottom: 0,
backgroundColor: 'black',
alignItems: 'center',
justifyContent: 'center',
},
buttonLabel: {
color: 'white',
fontWeight: 'bold'
},
headerLabel: {
fontSize: 16,
fontWeight: 'bold',
color: 'black'
},
})
Output SS

Related

Slider height is not changing with height property in react-native-swiper

so I'm fairly new to react-native. I'm trying to implement a carousel with react-native-swiper.
Issue -
I want to set the carousel height to 150px, for this I set the property height to 150px, with this the carousel height got changed to 150px but when I try to render a text component below carousel, it is not rendering just below the carousel.
import React from 'react';
import { View, Text, StyleSheet } from "react-native";
import Swiper from 'react-native-swiper';
const styles = StyleSheet.create({
wrapper: { backgroundColor: "black", height: 150 },
slide1: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#9DD6EB'
},
slide2: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#97CAE5'
},
slide3: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#92BBD9'
},
text: {
color: '#fff',
fontSize: 30,
fontWeight: 'bold'
}
})
const HomeScreen_ = () => {
return (
<>
<Swiper
style={styles.wrapper}
height={150}
showsButtons
autoplay
paginationStyle={{ height: 8, position: 'absolute', top: 130 }}
activeDot={
<View
style={{
backgroundColor: '#c3383833', width: 8,
height: 8, borderRadius: 4, marginLeft: 3,
marginRight: 3, marginTop: 3, marginBottom: 3
}} />
}>
<View style={styles.slide1}>
<Text style={styles.text}>Hello Swiper</Text>
</View>
<View style={styles.slide2}>
<Text style={styles.text}>Beautiful</Text>
</View>
<View style={styles.slide3}>
<Text style={styles.text}>And simple</Text>
</View>
</Swiper >
<Text style={{ height: 100, color: "black", }}>Just a Random Text</Text>
</>
)
};
export default HomeScreen_;
you can check this sample, in React Native, we have covered any component using View
import React from 'react';
import {View, Text, StyleSheet, SafeAreaView} from 'react-native';
import Swiper from 'react-native-swiper';
const SwiperExample = () => {
return (
<>
<View style={{flex: 0.3}}> // here
<Swiper
style={styles.wrapper}
showsButtons
autoplay
paginationStyle={{height: 8, position: 'absolute', top: 130}}
activeDot={
<View
style={{
backgroundColor: '#c3383833',
width: 8,
height: 8,
borderRadius: 4,
marginLeft: 3,
marginRight: 3,
marginTop: 3,
marginBottom: 3,
}}
/>
}>
<View style={styles.slide1}>
<Text style={styles.text}>Hello Swiper</Text>
</View>
<View style={styles.slide2}>
<Text style={styles.text}>Beautiful</Text>
</View>
<View style={styles.slide3}>
<Text style={styles.text}>And simple</Text>
</View>
</Swiper>
</View>
<Text style={{height: 100, color: 'black'}}>Just a Random Text</Text>
</>
);
};
const styles = StyleSheet.create({
wrapper: {backgroundColor: 'black', flex: 1},
slide1: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#9DD6EB',
},
slide2: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#97CAE5',
},
slide3: {
height: 150,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#92BBD9',
},
text: {
color: '#fff',
fontSize: 30,
fontWeight: 'bold',
},
});
export default SwiperExample;
I solved this issue by removing the height property in the wrapper object of StyleSheet and passing containerStyle={{ height: 150, flex: 0 }} as a prop in Swiper

I'm having trouble centering a Text component in React-Native

I'm creating a custom Header for my Screens and I'm trying to center the route name.
The problem is that there exist another component for my back button and it's making the centering really difficult.
Here is my component;
export default function Header({ navigation }) {
const route = useRoute()
console.log(route)
return (
<SafeAreaView>
<View style={styles.container}>
<TouchableOpacity
style={styles.paddedContainer}
onPress={() => navigation.goBack()}>
<Icon name="left" size={25} color={'black'} />
</TouchableOpacity>
<Text style={styles.routeName}>{route.params.title}</Text>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
width: '100%',
flexDirection: 'row',
backgroundColor: '#fff',
paddingBottom: 10,
elevation: 5,
zIndex: 5,
textAlign: 'center',
},
paddedContainer: {
marginLeft: SIZES.width * 0.05,
marginTop: SIZES.height * 0.02,
},
routeName: {
left: '50%',
fontSize: 22,
fontWeight: 'bold',
color: 'black',
marginTop: SIZES.height * 0.02,
},
})
I've tried textAlign, justifyContent, alignContent and all seems to be not working for my example.
First of all, your container need to have display:flex.
Second, there are two element inside container, so your title cannot be perfectly center.
Considered this, separate the component if you need another behaviour.
Here is the style that you need for center title element, but the <Icon/> will stay on the right. Play with flex-direction to make them in the way you want.
const styles = StyleSheet.create({
container: {
width: '100%',
display:'flex',
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: '#fff',
paddingBottom: 10,
elevation: 5,
zIndex: 5,
textAlign: 'center',
},
paddedContainer: {
marginLeft: SIZES.width * 0.05,
marginTop: SIZES.height * 0.02,
},
routeName: {
left: '50%',
fontSize: 22,
fontWeight: 'bold',
color: 'black',
marginTop: SIZES.height * 0.02,
},
})
Please find below Code:
export default function Header({ navigation }) {
const route = useRoute()
console.log(route)
return (
<SafeAreaView style={{flex:1,justifyContent:'center'}}>
<View style={styles.container}>
<TouchableOpacity
style={styles.paddedContainer}
onPress={() => navigation.goBack()}>
<Icon name="left" size={25} color={'black'} />
</TouchableOpacity>
<Text style={styles.routeName}>{route.params.title}</Text>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
width: '100%',
display:'flex',
flexDirection: 'row',
justifyContent: 'center',
backgroundColor: '#fff',
paddingBottom: 10,
elevation: 5,
zIndex: 5,
textAlign: 'center',
},
paddedContainer: {
marginLeft: SIZES.width * 0.05,
marginTop: SIZES.height * 0.02,
},
routeName: {
left: '50%',
fontSize: 22,
fontWeight: 'bold',
color: 'black',
marginTop: SIZES.height * 0.02,
},
})
Hope it will work!
I came up with an answer since the components of React-Native emit an onLayout prop, We could use it to get the width of an element. Then we can set the initial position of the object as absolute. Then set set the margin to device displays width and then get the width from the onLayout prop like so
<Text onLayout={(e) => setWidth(e.nativeEvent.layout.width)} />
Now that we have the width it's trivial matters to center the text. Just using the style from styleSheet and adding the margin. It would look something like this.
<Text style={{...styles.routeName, marginLeft: SIZES.width / 2 - width / 2}} onLayout={(e) => setWidth(e.nativeEvent.layout.width)} />
This centers it perfectly but with a couple of drawbacks. Since the event is emitted after the component is mounted the component sometimes jumps to place I've yet to come up with a better solution. Hope it helps some lost soul who comes across this.

Elevation doesn't work properly react native

I am trying to give shadow to my custom card component but the shadow cuts down the view like this:
Here is my code
import React from 'react'
import { View, StyleSheet, Text, Image, Dimensions } from 'react-native'
const { width } = Dimensions.get('window')
export default function CardCus() {
return (
<View style={{
justifyContent: 'center', alignItems: 'center', padding: 10
}}>
<View style={styles.container}>
<View style={{ width: 110, borderTopLeftRadius: 10, borderBottomLeftRadius: 10, }}>
<Image style={{ width: '100%', height: '100%', borderTopLeftRadius: 10, borderBottomLeftRadius: 10 }} source={{ uri: 'https://images.pexels.com/photos/6231818/pexels-photo-6231818.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940' }} />
</View>
<View style={{ margin: 10, padding: 5 }}>
<Text style={styles.title}>Title</Text>
<Text>Separator</Text>
<Text>Title</Text>
<Text>Title</Text>
</View>
</View>
</View>
)
}
const styles = StyleSheet.create(
{
container: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 2,
flexDirection: 'row',
borderRadius: 10,
borderColor: 'black',
borderWidth: 1,
height: 110,
width: width - 10,
},
title: {
fontWeight: 'bold'
}
}
)
I have tried many different style settings but none of them work. Is there a way to solve this issue? Thanks in advance.
So related to your question, it was hard to understand at first.
I just added the properties zIndex and backgroundColor to the container style and increased the value of the elevation and now it looks better. Also improved the readability.
See the comments in the improved code below:
import React from 'react';
import { View, StyleSheet, Text, Image, Dimensions } from 'react-native';
export default function CardCus() {
const imgUri =
'https://images.pexels.com/photos/6231818/pexels-photo-6231818.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940';
return (
<View style={styles.main}>
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image style={styles.image} source={{ uri: imgUri }} />
</View>
<View style={styles.textContainer}>
<Text style={styles.title}>Title</Text>
<Text>Separator</Text>
<Text>Title</Text>
<Text>Title</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 10, // changed to a greater value
flexDirection: 'row',
borderRadius: 10,
borderColor: 'black',
borderWidth: 1,
height: 110,
width: Dimensions.get('window').width - 10,
zIndex: 99, // added zIndex
backgroundColor: 'white', // added a background color
},
title: {
fontWeight: 'bold',
},
imageContainer: {
width: 110,
borderTopLeftRadius: 10,
borderBottomLeftRadius: 10,
backgroundColor: 'white',
},
image: {
width: '100%',
height: '100%',
borderTopLeftRadius: 10,
borderBottomLeftRadius: 10,
},
textContainer: {
margin: 10,
padding: 5,
backgroundColor: 'white',
},
main: {
justifyContent: 'center',
alignItems: 'center',
padding: 10,
},
});
You can adjust the values to make the shadow darker. And this is how it looks:

How to use flex in react-native correctly?

Problem:
I have created a react application. In there I have created a page header in my app which is common to all my components and the title of the Header will be change accordingly.
This image shows what my code does.
What I want to achieve is this.
This is my code of that Page header.
/* eslint-disable react-native/no-inline-styles */
import React, {Component} from 'react';
import {StyleSheet, View, Text, Image} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
class PageHeader extends Component {
render() {
return (
<View style={{zIndex: 0}}>
<LinearGradient
colors={['#fdc830', '#ff9a00']}
style={{alignItems: 'center', borderBottomLeftRadius: 80}}>
<View
// eslint-disable-next-line react-native/no-inline-styles
style={{
flexDirection: 'row',
marginTop: '10%',
marginBottom: '5%',
paddingTop: '5%',
}}>
<Text
style={{
fontSize: 18,
fontWeight: 'bold',
fontStyle: 'normal',
fontFamily: 'sans-serif',
letterSpacing: 0.81,
color: '#000104',
marginTop: '2%',
marginLeft: this.props.marginLeft,
marginRight: '2%',
}}>
{this.props.title}
</Text>
<Image
style={{
width: 20,
height: 10,
marginTop: this.props.marginTop,
}}
source={this.props.image}
/>
</View>
</LinearGradient>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
top: 0,
flex: 3,
},
homeHeader: {
flexDirection: 'column',
flex: 1,
},
homeHeaderImage: {
flexDirection: 'row',
},
headerText: {
fontSize: 18,
fontWeight: 'bold',
fontStyle: 'normal',
fontFamily: 'sans-serif',
letterSpacing: 0.81,
color: '#000104',
marginTop: '2%',
marginLeft: '30%',
marginRight: '3%',
},
hederContentContainer: {
flexDirection: 'row',
marginTop: '30%',
marginBottom: '10%',
},
qrCodeGeneraterContainer: {
alignItems: 'center',
justifyContent: 'center',
},
viewDetails: {
color: '#ff9a00',
fontSize: 12,
marginLeft: '75%',
fontWeight: 'bold',
marginTop: '2%',
marginBottom: '1%',
},
});
export default PageHeader;
This is how I am using this component in my home component.
<PageHeader
title="Settings"
image={require('../../../assets/settings.png')}
width={DEVICE_WIDTH / 14}
height={DEVICE_HEIGHT / 24}
marginTop="2%"
marginLeft="40%"
/>
What wrong with my code is it not showing the image fully. I tried so many ways to get the image full but I was unable to do so. And It shows different difference sizes on different device sizes as I have given the width based on the device with. Can someone help me to solve these two issues? Thank you.
Try this in your image component :
<Image
style={{
width: 20,
height: 20,
marginTop: this.props.marginTop,
resizeMode="contain"
}}
source={this.props.image}
/>
Hope it helps. feel free for doubts

TextInput full view in row direction

I ma new to React native development. In my application I have login screen. In laogin screen I have two text inputs along with images. I have taken image and Text input in one view and given flex direction as row. And I have given text input as alignSelf stretch. So here my issue is I need full length of text input along with image. But if I removed flex direction then will get full length of the screen. The following is the code
import React, {Component} from 'react';
import {StyleSheet, Text, View,TextInput,TouchableOpacity,StatusBar,Image} from 'react-native';
export default class App extends Component {
static navigationOptions = {
title: "Welcome",
header: null,
}
render() {
// const { navigate } = this.props.navigation
return (
<View style={styles.container}>
<StatusBar
barStyle="light-content"
backgroundColor="#2f5597"
/>
<Image source={require('../../app/images/ic_accountlist.png')} style={styles.logo}/>
<View style={styles.loginView}>
<View >
<Image source={require('../../app/images/ic_userid.png')} />
<TextInput placeholder="Acct No/User Id" style={styles.textInput} underlineColorAndroid={'rgb(0,0,0)'}></TextInput>
</View>
<View style={styles.user}>
<Image source={require('../../app/images/ic_password.png')} />
<TextInput placeholder="Password" style={styles.textInput} underlineColorAndroid={'rgb(0,0,0)'}></TextInput>
</View>
</View>
<TouchableOpacity style={styles.btnLogin} onPress={this.login}><Text style={{color: 'white'}}>Log In</Text></TouchableOpacity>
</View>
);
}
login=()=>{
// alert("testing......");
this.props.navigation.navigate('Profile');
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCF0',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color:'#FF0000',
},
textInput: {
alignSelf: 'stretch',
padding: 10,
marginLeft: 5,
marginRight:0,
},
btnLogin:{
borderRadius: 10,
backgroundColor: '#2f5597',
padding: 10,
marginTop: 20,
paddingLeft: 50,
paddingRight: 50,
alignSelf: 'center',
},
user:{
flexDirection: 'row',
},
logo :{
marginTop: 100,
alignSelf: 'center',
},
loginView:{
marginTop: 60,
}
});
And the following is the output I am getting
And here I need the text input full along with image. Like the below
There is no need to use the alignSelf property. Instead, you have to use flex: 1:
textInput: {
flex: 1,
padding: 10,
marginLeft: 5,
marginRight: 0,
},
flex: 1 is a shorthand notation, so you could also use explicitly flexGrow: 1 to achieve the same effect:
textInput: {
flexGrow: 1,
padding: 10,
marginLeft: 5,
marginRight: 0,
},
You can read more about flex on MDN.
Result (ignore the different icon):
You need to add flex: 1 to textInput style
textInput: {
alignSelf: 'stretch',
padding: 10,
marginLeft: 5,
marginRight:0,
flex: 1
}