I'm currently developing an app to be used in an Android tablet, unfortunately I got comfortable and added too many features in web view before testing again on android and now they look quite different.
I have a few elements in a flex-box view with flex-direction 'row', this is how they look on the browser and how they should look:
Then the same app on android looks like this:
You can see the two lines with inputs without proper height to fit the text, and a third line on the bottom already from another input.
This is the component code (I removed one input line to make it simpler):
<View>
<Text style={styles.header}>
{LanguageService(language).form.personalData}:
</Text>
<View style={styles.twoColumns}>
<View style={styles.inputWrapper}>
<Text>
{LanguageService(language).form.firstName}:
</Text>
<TextInput
style={styles.input}
onChangeText={formikProps.handleChange('firstName')}
value={formikProps.values.firstName}
maxLength={20}
/>
</View>
<View style={styles.inputWrapper}>
<Text>
{LanguageService(language).form.phone}:
</Text>
<TextInput
style={styles.input}
onChangeText={formikProps.handleChange('phoneNumber')}
value={formikProps.values.phoneNumber}
keyboardType='phone-pad'
maxLength={15}
/>
</View>
</View>
</View>
And here is the style:
const styles = StyleSheet.create({
twoColumns: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
},
inputWrapper: {
width: '48%',
flexDirection: 'row',
justifyContent: 'space-around',
borderBottomWidth: 1,
borderBottomColor: 'black',
margin: 10,
},
input: {
flexGrow: 1,
paddingLeft: 5,
},
header: {
color: 'red',
fontWeight: 'bold',
fontSize: 22,
},
}
I think you can achieve the shape in the first image with this structure:
<View style={styles.container}>
<View style={styles.headerContainer}>
<Text style={styles.header}>
{LanguageService(language).form.personalData}:
</Text>
</View>
<View style={styles.inputsContainer}>
<View stlye={styles.leftContainer>
<View style={styles.inputWrapper}>
<Text>
{LanguageService(language).form.firstName}:
</Text>
<TextInput
style={styles.input}
onChangeText={formikProps.handleChange('firstName')}
value={formikProps.values.firstName}
maxLength={20}
/>
</View>
</View>
<View stlye={styles.rightContainer>
<View style={styles.inputWrapper}>
<Text>
{LanguageService(language).form.phone}:
</Text>
<TextInput
style={styles.input}
onChangeText={formikProps.handleChange('phoneNumber')}
value={formikProps.values.phoneNumber}
keyboardType='phone-pad'
maxLength={15}
/>
</View>
</View>
</View>
</View>
Style:
const styles = StyleSheet.create({
container: {
display: 'flex',
flexDirection: 'column'
},
headerContainer: {
flex: 0.5
},
inputsContainer: {
flex: 1,
display: 'flex',
flexDirection: 'row'
},
leftContainer: {
flex: 1
},
rightContainer: {
flex: 1
}
inputWrapper: {
width: '48%',
flexDirection: 'row',
justifyContent: 'space-around',
borderBottomWidth: 1,
borderBottomColor: 'black',
margin: 10,
},
input: {
flexGrow: 1,
paddingLeft: 5,
},
header: {
color: 'red',
fontWeight: 'bold',
fontSize: 22,
},
}
I manage to solve this by removing the following line:
const styles = StyleSheet.create({
twoColumns: {
flex: 1,
}
}
Related
I want to make feed screen and this is what i want to achieve for every post item.
This is what i have currently . I thought this will do the work. Am I making a mistake somewhere or I need to add someting else to the styles? I struggle with design and thought this will be enough to structure the components. For example, I expected the image to be the top element but somehow it is in the middle... Also, when I have such problems, how to cope with them, any tips?
<View style={styles.wrapper}>
<Opacity onPress={props.onPostSelect}>
<View style={{ ...styles.postContainer, ...props.style }}>
{/* thumbnail */}
<View style={styles.thumbnailContainer}>
<Image
resizeMode="contain"
source={{ uri: props.item.thumbnailURL }}
style={styles.thumbnail}
/>
</View>
{/* thumbnail end*/}
{/* info container */}
<View style={styles.infoContainer}>
<View style={styles.postDetailsContainer}>
{/* //TITLE */}
<View style={styles.title}>
<Text style={styles.text} numberOfLines={1}>
{props.item.title}
</Text>
</View>
{/* //TITLE end*/}
{/* LIKES/VIEWS */}
<View style={styles.likesAndViewsContainer}>
<Text style={styles.text}>{props.item.views} views | </Text>
{/* LIKES */}
<View style={styles.likesContainer}>
<MaterialIcons name="thumb-up" color="white" size={18} />
<Text style={styles.text}> {props.item.likes} </Text>
</View>
</View>
</View>
</View>
</View>
</Opacity>
</View>
the styles :
const styles = StyleSheet.create({
postContainer: {
justifyContent: "center",
borderWidth: 7,
borderColor: "brown",
borderRadius: 2,
backgroundColor: "pink",
marginHorizontal: 5,
height: "95%",
overflow: "hidden",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
},
wrapper: {
flex: 1,
flexGrow: 1,
height: 500,
width: "100%",
backgroundColor: Colors.secondaryColors.lightGray,
overflow: "hidden",
},
title: {
flexDirection: "column",
color: "white",
height: "80%",
},
likesAndViewsContainer: {
flexDirection: "row",
justifyContent: "flex-start",
overflow: "hidden",
},
text: {color:black},
likesContainer: {
flexDirection: "row",
},
thumbnail: {
flex: 1,
width: 100,
height: "100%",
position: "absolute",
},
thumbnailContainer: {
flex: 1,
height: "100%",
width: "100%",
marginVertical: 10,
position: "absolute",
right: 10,
left: 10,
},
infoContainer: {
flexDirection: "row",
},
postDetailsContainer: {
color: "white",
fontSize: 16,
flexDirection: "column",
},
});
i think there's something to do with your position:'absolute' and flex:1.
I've cleaned it up a bit, and do tell me, if this is what you're going for
<View style={styles.wrapper}>
<View style={styles.postContainer}>
<View style={styles.thumbnailContainer}>
<Image
resizeMode="contain"
source={{ uri: props.item.thumbnailURL }}
style={styles.thumbnail}
/>
</View>
<View style={styles.infoContainer}>
<Text style={styles.text} numberOfLines={1}>{props.item.title}</Text>
<View style={styles.likesAndViewsContainer}>
<Text style={styles.text}>{props.item.view} views | </Text>
<View style={styles.likesContainer}>
<MaterialIcons name="thumb-up" color="white" size={18} />
<Text style={styles.text}> {props.item.likes} </Text>
</View>
</View>
</View>
</View>
</View>
the styles:
const styles = StyleSheet.create({
postContainer: {
borderWidth: 1,
borderColor: "brown",
backgroundColor: "pink",
padding:15,
},
wrapper: {
flex:1,
backgroundColor: 'gray',
},
likesAndViewsContainer: {
flexDirection: "row",
justifyContent: "flex-start",
},
text: {
color:'black',
marginBottom:15,
fontWeight:'bold',
},
likesContainer: {
flexDirection: "row",
},
thumbnailContainer:{
height: 100,
width:100,
borderWidth:1,
alignSelf:'center',
},
thumbnail: {
height: 100,
width:100,
},
infoContainer: {
marginTop:15,
},
});
Layout overlapping on text input in react native as you can see in the images.
I have experimented with keyboardAvoidingView and keyboardAwareScrollView but I just cant fix it or I am implementing them incorrectly.
How to avoid keyboard from changing your flex layout? What's the industry standard? keyboardAvoidingView? I find that inconsistent or have not understood it conceptually. My approach usually is wrapping the entire code with either keyboardAwareScrollView or keyboardAvoidingView. Do I only do it over the textInput component?
const InterviewAlignment = ({navigation}) => {
return (
<View style={styles.container}>
<View style={styles.header}>
</View>
<View style={styles.main}>
<View
style={{
flex: 1,
justifyContent: 'space-between',
}}>
<View
style={{
flex: 1,
backgroundColor: 'red',
}}>
</View>
<View style={styles.modeContainer}>
</View>
<View style={{flex: 1}}>
<Text style={styles.text}>Link Address</Text>
<TextInput
style={styles.linkInput}
/>
</View>
</View>
<View style={{flex: 1, backgroundColor: 'red'}}>
</View>
<View style={{flex: 1.5, backgroundColor: 'black'}}>
</View>
</View>
</View>
);
};
//RFValue is just a responsive wrapper
const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: RFValue(16),
minHeight: RFValue(56),
backgroundColor: '#B1C59B',
},
text: {
fontSize: RFValue(15),
color: 'black',
},
main: {
flex: 1,
padding: 15,
},
modeContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
flex: 1,
backgroundColor: 'yellow',
},
linkInput: {
marginHorizontal: RFValue(40),
padding: 0,
paddingTop: 2,
borderBottomWidth: RFValue(1),
borderBottomColor: '#C4C4C4',
},
});
You can set height instead of flex in styling
My modal -- noDevicesModalContainer -- is taking up an enormous amount of the screen and I can't work out why.
I am very new to React Native and web development generally, so please do not be afraid to overexplain!
Thank you in advance for your suggestions.
class DevicesEmptyScreen extends Component {
render() {
return (
<View style={styles.screen}>
<View style={styles.noDevicesImage}>
<Image
source={require('./../../../android/app/src/main/res/drawable/no_devices.png')}
/>
</View>
<View style={styles.noDevicesTextContainer}>
<Text style={styles.noDevicesText}>You do not have any devices yet</Text>
</View>
<View style={styles.noDevicesModalContainer}>
<Text style={[styles.noDevicesText, styles.noDevicesModalText]}>
In case no devices have been assigned, please contact your administrator
</Text>
</View>
</View>
)
}
}
export default DevicesEmptyScreen
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
noDevicesImage: {
flex: 1,
marginTop: 40
},
noDevicesTextContainer: {
flex: 1,
justifyContent: 'center'
},
noDevicesText: {
color: '#89C7C8',
padding: 10
},
noDevicesModalContainer: {
flex: 1,
backgroundColor: '#EBF5F6',
borderRadius: 10,
marginHorizontal: 30,
marginVertical: 30
},
noDevicesModalText: {
marginLeft: 20
}
})
As per Modal documentation. Try this
<Modal transparent={true}
visible={this.state.isVisible}
onRequestClose={this.closeModal}>
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'}}>
<View style={{
width: 300,
height: 300}}>
...
</View>
</View>
</Modal>
Im trying to make a flatlist with some data and a button on each row.
I have tried to do it in a typical "web" fashion, with nested views and formating the elements relative to their parent, but with no success.
this is the current structure of the list:
<View style={styles.row}>
<View style={styles.rowinfo}>
<View>
<Text style={styles.primaryID}>{item.name ? item.name : item.phoneNumber}</Text>
<Text style={styles.secondaryID}>{item.name ? item.phoneNumber : 'Ukjent innringer'}</Text>
</View>
<View>
<Text style={styles.textalignRight}>Varighet: {item.durationDisplay}</Text>
<Text style={styles.textalignRight}>{item.dateStringTime}</Text>
</View>
</View>
<TouchableOpacity style={styles.rowicon}>
<View style={styles.ban_icon}>
<Icon
name='ban'
type='font-awesome'
color='#FFF'
/>
</View>
</TouchableOpacity>
</View>
And here is my styling:
const styles = StyleSheet.create({
row: {
flex: 1,
marginTop: 1,
paddingVertical: 10,
paddingHorizontal: 15,
flexDirection: "row",
justifyContent: "space-between",
borderBottomWidth: 1,
borderBottomColor: '#f9f9f9'
},
rowinfo:{
flexDirection: "row",
alignSelf: 'stretch'
},
primaryID: {
fontWeight: 'bold'
},
textalignRight: {
textAlign: 'right'
},
rowbt: {
justifyContent: "center",
alignItems: "center",
backgroundColor: 'red'
},
ban_icon: {
color: '#FFF',
fontWeight: 'bold',
fontSize: 14,
marginHorizontal: 8
}
});
I im trying to make it look like this:
But i keep getting this:
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.row}>
<View style={styles.rowinfo}>
<View>
<Text style={styles.primaryID}>{'Phone Number'}</Text>
<Text style={styles.secondaryID}>{'Ukjent innringer'}</Text>
</View>
</View>
<View style={{ flexDirection: 'row'}}>
<View>
<Text style={styles.textalignRight}>Varighet: {'1m og 20s'}</Text>
<Text style={styles.textalignRight}>{'13:23:11'}</Text>
</View>
<TouchableOpacity style={styles.ban_icon}>
<View style={styles.ban_icon} />
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
},
row: {
backgroundColor: 'green',
width: '100%',
marginTop: 1,
paddingVertical: 10,
paddingHorizontal: 15,
flexDirection: "row",
justifyContent: "space-between",
borderBottomWidth: 1,
borderBottomColor: '#f9f9f9'
},
rowinfo:{
flex: 1,
flexDirection: "row",
},
primaryID: {
fontWeight: 'bold'
},
textalignRight: {
textAlign: 'right'
},
ban_icon: {
padding: 10,
backgroundColor: 'red',
marginLeft: 10,
}
});
Check the snack: https://snack.expo.io/#legowtham/43c687
I was able to get my desired result by using absolute positioning.
i want to align 3 Views in a row:
|Icon| |Title| |Buttons|
The Title can be more than one line. The buttons are 0-3 Buttons, so their width is unknown to me.
Now the problem is, if I got more than one line in the title the buttons are cut off. How can i solve this and make sure the buttons are always on the screen and the title just has the space that is left?
On this screenshot 2 listitems are visible. Both should have 3 buttons on the right, but with the long title in the second row, the buttons are cut off
render() {
return (
<TouchableHighlight style={styles.view} underlayColor={'#eee'} onPress={this.props.navigateToDetails}>
<View style={{flex: 1}}>
<View style={styles.header}>
<View style={styles.headerTitle}>
<MaterialIcons style={styles.icon} name={"worker"}/>
<MentionsText style={styles.title}
>
{this.props.siteVisitNote.title}
</MentionsText>
</View>
<View style={styles.buttons}>
<FontAwesomeIcons style={styles.icon} name="tag"/>
{Utils.objectExists(this.props.siteVisitNote.attachments) || true ?
<FontAwesomeIcons style={styles.icon} name="paperclip"/> : null}
{Utils.objectExists(this.props.siteVisitNote.images) || true ?
<FontAwesomeIcons style={styles.icon} name="picture-o"/> : null}
</View>
</View>
<MentionsText style={styles.text}
>{this.getText()}</MentionsText>
</View>
</TouchableHighlight>
)
}
}
const styles = StyleSheet.create({
header: {
flexDirection: 'row',
justifyContent: "space-between",
},
headerTitle: {
flexDirection: 'row'
},
view: {
flex: 1,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#efeff4',
padding: 8,
minHeight: 40,
},
buttons: {
flexDirection: "row",
alignSelf: 'flex-end',
},
icon: {
fontSize: 20,
paddingRight: 5,
color: "#333333",
padding: 8
},
title: {
color: "#333333",
fontSize: 14,
fontWeight: 'bold',
padding: 8,
},
text: {
color: "#333333",
fontSize: 14,
padding: 8
}
});
Thanks!
Add flex: 1 to headerTitle, and title.
If that doesn't work see my working example of this layout here which you can compare.
https://gist.github.com/WilliamIPark/2ad3ecf47c5c1e559086e4b10d0cf018
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
ScrollView
} from 'react-native';
export default class App extends Component {
render() {
return (
<ScrollView
style={{ backgroundColor: '#edf2f9'}}
contentContainerStyle={styles.container}
>
<View style={styles.card}>
<View style={styles.header}>
<View style={styles.iconTitle}>
<View style={styles.icon} />
<Text>Hello world</Text>
</View>
<View style={styles.buttonWrap}>
<View style={styles.button} />
<View style={styles.button} />
<View style={styles.button} />
</View>
</View>
<View>
<Text>
Some other content...
</Text>
</View>
</View>
<View style={styles.card}>
<View style={styles.header}>
<View style={styles.iconTitle}>
<View style={styles.icon} />
<Text style={styles.title}>
Hello world this is some really long title right here, that
goes on and on and on. And then some!
</Text>
</View>
<View style={styles.buttonWrap}>
<View style={styles.button} />
<View style={styles.button} />
<View style={styles.button} />
</View>
</View>
<View>
<Text>
Some other content...
</Text>
</View>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#edf2f9',
},
card: {
backgroundColor: 'white',
height: 200,
width: 320,
shadowColor: 'black',
shadowOpacity: 0.25,
shadowOffset: {x: 10, y: 10},
padding: 10,
marginTop: 10,
},
header: {
borderBottomWidth: 0.5,
borderBottomColor: 'lightgrey',
flexDirection: 'row',
marginBottom: 10,
justifyContent: 'space-between',
},
iconTitle:{
flexDirection: 'row',
flex: 1,
marginBottom: 10,
},
icon: {
height: 24,
width: 24,
backgroundColor: 'black',
marginRight: 5,
},
title: {
flex: 1,
},
buttonWrap: {
flexDirection: 'row',
},
button: {
height: 24,
width: 24,
backgroundColor: 'red',
marginLeft: 5,
}
});