TextInput full view in row direction - react-native

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
}

Related

Implementing a feedback screen in 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

React Navigation (native): Overflow visible not working on custom header

I'm implementing a custom header for #react-navigation/native-stack. Using React Navigation v6.
One of the elements within the custom header has a native shadow on iOS added (via the style prop). The shadow is a tad bigger than the header and unfortunately, I can't get it to display beyond the boundaries of the header. Of course, I've tried using overflow: visible on basically every component in the tree, but no success. The shadow is clipped off:
Here's my custom header:
function CustomHeader(props: NativeStackHeaderProps) {
const { options, route, navigation } = props;
const insets = useSafeAreaInsets();
const headerHeight = Helpers.getHeaderHeight(insets);
return (
<View style={{
height: headerHeight,
paddingTop: insets.top,
width: '100%',
backgroundColor: Colors.white,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingLeft: 20,
paddingRight: 20,
overflow: 'visible',
}}
>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-start',
}}
>
{ options.headerLeft ? options.headerLeft({ canGoBack: false }) : (
<TouchableOpacity
onPress={() => route.name === 'Home'
? null
: navigation.reset({ index: 0, routes: [{ name: 'Home' }] })}
>
<Image
style={{ width: Sizing.logo, height: Sizing.logo }}
source={Logo}
/>
</TouchableOpacity>
)}
</View>
<Text style={{
textAlign: 'center', color: Colors.purple,
}}
>
{(options.title || route.name).toUpperCase()}
</Text>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-end', overflow: 'visible',
}}
>
{ options.headerRight ? options.headerRight({ canGoBack: false }) : null}
</View>
</View>
);
}
The button on the right with the shadow is passed in through the headerRight option and contains this shadow style:
nativeShadow: {
shadowColor: Colors.gray,
shadowOffset: { width: 0, height: 8 },
shadowRadius: Colors.shadows.gray.distance,
shadowOpacity: 0.5,
},
Any idea what I could try next? I don't want to increase the headers' height since this would break the layout elsewhere.
I had a similar problem with the menu. I think i was taking another way and maybe you should try it.
Be sure that all the parent elements has at least the same height than the navmenu's height.
import React, { Component } from 'react';
import { TouchableOpacity, StyleSheet, Image, View, Text } from 'react-native';
const styles = StyleSheet.create({
menuParent: {
marginLeft: 30,
justifyContent: "flex-start",
alignItems: "flex-end",
flex: 1,
height: 250
},
btnContainer: {
width: 40,
height: 40,
elevation: 50,
zIndex: 50,
marginTop: 5
},
image: {
width: 40,
height: 40,
},
menuContainer: {
position: "absolute",
top: 5,
left: -5,
right: -5,
padding: 20,
borderRadius: 10,
elevation: 10,
zIndex: 10,
flex: 1,
height: 230,
backgroundColor: "#fff",
}
});
export default class DefaultHeaderMenu extends Component {
state = {
menuVisible: false
};
constructor(props) {
super(props);
}
render() {
return (
<View style={ styles.menuParent }>
{this.state.menuVisible ? <View style={ styles.menuContainer }></View> : null }
<TouchableOpacity
style={ styles.btnContainer }
onPress={ () => this.setState({ menuVisible: !this.state.menuVisible }) }
>
<Image
source={ require('#/assets/img/menu.png') }
style={ styles.image }
/>
</TouchableOpacity>
</View>
);
}
}
This is the component i used and the passed it to nav as headerRight element.
In my case, the problem was that height: 250 was missing in menuParent.
I hope it helps you and good luck
I had a problem like this once and fixed it by using 'zIndex'. Try setting it as the* max index in your project. Hope it helps

I am trying to implement text change and edit ends in TextInput using react-native but it's not quite working. Can any one help me?

I am trying to implement text change and edit ends in TextInput using react-native but it's not quite working.
See the Screenshot Here
Currently, when changing the price by touch input, the price is not affected when click off.
Here are my files
CartItem.js:
import React from "react";
import {
View,
TextInput,
Image,
TouchableOpacity,
StyleSheet,
Platform,
Alert,
} from "react-native";
//Colors
import Colors from "../../../utils/Colors";
//NumberFormat
import NumberFormat from "../../../components/UI/NumberFormat";
//Icon
import { MaterialCommunityIcons } from "#expo/vector-icons";
import CustomText from "../../../components/UI/CustomText";
//PropTypes check
import PropTypes from "prop-types";
export class CartItem extends React.PureComponent {
render() {
const { item, onAdd, onDes, onRemove } = this.props;
const AddItemHandler = async () => {
await onAdd();
};
const sum = +item.item.price * +item.quantity;
const checkDesQuantity = async () => {
if (item.quantity == 1) {
Alert.alert(
"Clear cart",
"Are you sure you want to remove the product from the cart?",
[
{
text: "Cancel",
},
{
text: "Yes",
onPress: onRemove,
},
]
);
} else {
await onDes();
}
};
return (
<View style={styles.container}>
<View style={styles.left}>
<Image
style={{
width: "100%",
height: 90,
resizeMode: "stretch",
borderRadius: 5,
}}
source={{ uri: item.item.thumb }}
/>
</View>
<View style={styles.right}>
<View
style={{ flexDirection: "row", justifyContent: "space-between" }}
>
<CustomText style={styles.title}>{item.item.filename}</CustomText>
<View>
<TouchableOpacity onPress={onRemove}>
<MaterialCommunityIcons name='close' size={20} color='#000' />
</TouchableOpacity>
</View>
</View>
<CustomText style={{ color: Colors.grey, fontSize: 12 }}>
Provided by Brinique Livestock LTD
</CustomText>
<NumberFormat price={sum.toString()} />
<View style={styles.box}>
<TouchableOpacity onPress={checkDesQuantity} style={styles.boxMin}>
<MaterialCommunityIcons name='minus' size={16} />
</TouchableOpacity>
Code that I would like to be fixed starts here.
<View>
<TextInput
keyboardType='numeric'
onEndEditing={AddItemHandler}
style={styles.boxText}>{item.quantity}</TextInput>
</View>
Code that I would like to be fixed ends here.
<TouchableOpacity
onPress={AddItemHandler}
style={styles.boxMin}>
<MaterialCommunityIcons name='plus' size={16} />
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
CartItem.propTypes = {
item: PropTypes.object.isRequired,
onAdd: PropTypes.func.isRequired,
onRemove: PropTypes.func.isRequired,
onDes: PropTypes.func.isRequired,
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginHorizontal: 10,
height: 110,
borderBottomWidth: 1,
borderBottomColor: Colors.light_grey,
flexDirection: "row",
paddingVertical: 10,
alignItems: "center",
backgroundColor: "#fff",
paddingHorizontal: 10,
borderRadius: 5,
marginTop: 5,
},
left: {
width: "35%",
height: "100%",
alignItems: "center",
},
right: {
width: "65%",
paddingLeft: 15,
height: 90,
// overflow: "hidden",
},
title: {
fontSize: 14,
},
box: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
height: Platform.OS === "ios" ? 30 : 25,
backgroundColor: Colors.grey,
width: 130,
borderRadius: 5,
paddingHorizontal: 15,
marginTop: 5,
},
boxMin: {
width: "30%",
alignItems: "center",
},
boxText: {
fontSize: 16,
backgroundColor: Colors.white,
padding: 5,
},
});
Use onBlur instead of onEndEditing.
How should the input end triggered?
After a time?
When user hits enter?
When user taps anywhere to close software keyboard?
Instead of
onEndEditing={AddItemHandler}
Use:
onBlur={(e) => {AddItemHandler(e.nativeEvent.text)}}
And ensure that AddItemHandler can handle the value in e.nativeEvent.text.

Flex is not splitting components equally in react native

I'm trying to make a layout like this:
In order to do so, I've made two components named HalfWidthFullHeightCard and HalfWithHalfHeightCard.
I've created the HalfWidthFullHeightCell component as?
<TouchableOpacity onPress={pressEvent}>
<ImageBackground
source={sourcePath}
imageStyle={{ borderRadius: 8, resizeMode: 'cover', width: '100%' }}
style={styles.halfWidthCard}>
<Text style={styles.halfWidthCardHeading}>{heading}</Text>
<Text style={styles.halfWidthCardText}>{cardText}</Text>
</ImageBackground>
</TouchableOpacity>
...
halfWidthCard: {
backgroundColor: colors.brightYellow,
marginBottom: 10,
borderRadius: 8,
},
Based on the cardText the width of the card is calculated automatically and in the halfWidthCardText StyleSheet I've only had padding: 10
Next for HalfWithHalfHeightCard everything is the same except for the styling which is:
...
smallHalfWidthCard: {
backgroundColor: colors.brightYellow,
borderRadius: 8,
marginBottom: 10
},
smallHalfWidthCardHeading: {
padding: 10,
},
smallHalfWidthCardText: {
padding: 10,
},
Where I'm putting both of these components together I'm doing:
<ScrollView contentContainerStyle={{padding: 15}}>
<View style={{flexDirection: 'row',}}>
<HalfWidthFullHeightCell />
<View>
<HalfWithHalfHeightCell />
<HalfWithHalfHeightCell />
</View>
</View>
</ScrollView>
Now there are two problems:
Consider the gray area as the width of the device. The HalfWidthFullHeightCard takes 100% of the space and
The HalfWithHalfHeightCard are outside of the screen and also not of the same height as HalfWidthFullHeightCard.
So, how can I make these components flexible so that they adapt to the layout as screen size changes?
I would have made it like this
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
const ScreenWidth = Dimensions.get('window').width;
export default function App() {
return (
<View style={styles.container}>
<View style={styles.WholeBox}>
<View style={styles.Block}></View>
<View style={{ flex: 1 }}>
<View style={styles.Block}></View>
<View style={styles.Block}></View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
WholeBox: {
width: ScreenWidth,
height: 300,
flexDirection: 'row',
},
Block: {
flex: 1,
backgroundColor: '#DDA73A',
margin: 6,
borderRadius: 8,
},
});
Working Example Here

In React Native, how do I put a view on top of another view, with part of it lying outside the bounds of the view behind?

I'm trying to make a layout as per below with React Native.
How do I specify the position of B relative to A?
With iOS Interface Builder and autoconstraints, this can very explicitly be done and is a breeze. It's not so obvious how one might achieve this with React Native.
Add the following style to the "floating" view:
position: 'absolute'
You may also need to add a top and left value for positioning.
The above solutions were not working for me. I solved it by creating a View with the same background colour as the parent and added negative margin to move the image upwards.
<ScrollView style={{ backgroundColor: 'blue' }}>
<View
style={{
width: '95%',
paddingLeft: '5%',
marginTop: 80,
height: 800,
}}>
<View style={{ backgroundColor: 'white' }}>
<Thumbnail square large source={{uri: uri}} style={{ marginTop: -30 }}/>
<Text>Some Text</Text>
</View>
</View>
</ScrollView>
and I got the following result.
You can use zIndex for placing a view on top of another. It works like the CSS z-index property - components with a larger zIndex will render on top.
You can refer: Layout Props
Snippet:
<ScrollView>
<StatusBar backgroundColor="black" barStyle="light-content" />
<Image style={styles.headerImage} source={{ uri: "http://www.artwallpaperhi.com/thumbnails/detail/20140814/cityscapes%20buildings%20hong%20kong_www.artwallpaperhi.com_18.jpg" }}>
<View style={styles.back}>
<TouchableOpacity>
<Icons name="arrow-back" size={25} color="#ffffff" />
</TouchableOpacity>
</View>
<Image style={styles.subHeaderImage} borderRadius={55} source={{ uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Albert_Einstein_1947.jpg/220px-Albert_Einstein_1947.jpg" }} />
</Image>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white"
},
headerImage: {
height: height(150),
width: deviceWidth
},
subHeaderImage: {
height: 110,
width: 110,
marginTop: height(35),
marginLeft: width(25),
borderColor: "white",
borderWidth: 2,
zIndex: 5
},
You can use this OverlayContainer. The trick is to use absolute with 100% size. Check below an example:
// #flow
import React from 'react'
import { View, StyleSheet } from 'react-native'
type Props = {
behind: React.Component,
front: React.Component,
under: React.Component
}
// Show something on top of other
export default class OverlayContainer extends React.Component<Props> {
render() {
const { behind, front, under } = this.props
return (
<View style={styles.container}>
<View style={styles.center}>
<View style={styles.behind}>
{behind}
</View>
{front}
</View>
{under}
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
center: {
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
},
behind: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
import React, {Component} from 'react';
import {StyleSheet, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View>// you need to wrap the two Views an another View
<View style={styles.box1}></View>
<View style={styles.box2}></View>
</View>
);
}
}
const styles = StyleSheet.create({
box1:{
height:100,
width:100,
backgroundColor:'red'
},
box2:{
height:100,
width:100,
backgroundColor:'green',
position: 'absolute',
top:10,
left:30
},
});
You can use react-native-view-overflow plugin for placing a view on top of another. It works like the CSS z-index property.
import ViewOverflow from 'react-native-view-overflow';
<ViewOverflow />
<View style={[styles2.cardBox, { marginTop: 50 }]}>
<View style={[styles2.cardItem]} >
<Text style={styles2.cardHeader}>userList</Text>
</View>
<View style={[styles2.cardContent]}>
<Text style={styles2.text}>overflow: "visible"</Text>
</View>
<View style={[styles2.cardItemFooter]} >
<Text style={styles2.cardTextFooter}>...</Text>
</View>
</View>
</ViewOverflow>
const styles2 = StyleSheet.create({
cardBox: {
borderLeftWidth: 0,
borderTopWidth: 0,
backgroundColor: "transparent",
borderWidth: 1,
borderColor: "#d0d0d0",
width: '94%',
alignSelf: 'center',
height: 200,
position: "relative",
borderRadius: 15,
overflow: "visible" // doesn't do anything
},
cardContent: {
textAlign: "right",
backgroundColor: "transparent",
marginTop: 15,
alignSelf: 'flex-end',
padding: 5,
},
cardHeader: {
color: '#fff',
fontFamily: 'Vazir',
fontSize: 12
},
cardItem: {
backgroundColor: "#3c4252",
borderRadius: 3,
position: "absolute",
top: -10,
right: -5,
width: 50,
height: 20,
paddingRight: 5,
},
})
The easiest way to achieve this is with a negative margin.
const deviceWidth = RN.Dimensions.get('window').width
a: {
alignItems: 'center',
backgroundColor: 'blue',
width: deviceWidth,
},
b: {
marginTop: -16,
marginStart: 20,
},
You can use elevation property for Android if you don't mind the shadow.
{
elevation:1
}
Try this:
style = {{position: 'absolute', bottom: 20, left: 20, elevation: 100}}
Based on the example above i've created a component which stacks all childeren on top of each other. You could even nest OverlayContainers inside OverlayContainers.
Usage:
<OverlayContainer>
<View style={{backgroundColor:'red', width:150, height: 150}}></View>
<View style={{backgroundColor:'yellow', width:50, height: 50}}></View>
<Text>Just some text</Text>
</OverlayContainer>
Output:
import React, { FC, PropsWithChildren } from 'react'
import { StyleSheet, View } from 'react-native'
export const OverlayContainer: FC<PropsWithChildren<unknown>> = (props) => {
return (
<View style={styles.container}>
{props.children.map((child, index) => (
<View style={styles.child} key={index}>
{child}
</View>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
},
child: {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%'
}
})
<SafeAreaView style={{ flex: 1 }} >
<View style={{ height: Dimensions.get('window').height / 2, backgroundColor: 'blue', justifyContent: 'center' }}>
<Text style={{ fontSize: 25, alignSelf: 'center' }} >A</Text>
<View style={{ justifyContent: 'center', height: 100, width: 100, backgroundColor: 'yellow', position: 'absolute', left: 20, top: Dimensions.get('window').height / 2 - 70 }}>
<Text style={{ fontSize: 22, alignSelf: 'center' }} >B</Text>
</View>
</View>
</SafeAreaView>