How do I make one <View> take all available space when there is something else on the same row? - react-native

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.

Related

How to define height to an element in react native in android?

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,
}
}

Touchables in react native

I am trying to add some space in the middle of two touchable components wrapped in a view
How do i go about doing that, I will include my style sheet
return (
<>enter code here
<View style={styles.container}>
<View style={styles.scrollContainer}>
<ScrollView
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
>
{images.map((image) => (
<Image key={image} style={styles.image} source={image} />
))}
</ScrollView>
</View>
<View style={styles.btn}>
`enter code here`<LinearGradient
colors={["#0A5640", "#0A5640"]}
style={{ alignItems: "center", borderRadius: 10 }}
>
<TouchableOpacity onPress={() => navigation.navigate("SignIn")}>
<Text style={styles.btnAuth}>Sign In</Text>
</TouchableOpacity>
</LinearGradient>
<LinearGradient
colors={["#FFC72A", "#FFC72A"]}
style={{ alignItems: "center", borderRadius: 10 }}
>
<TouchableOpacity
onPress={() => navigation.navigate("CreateAccount")}
>
<Text style={styles.btnAuth}>Sign Up</Text>
</TouchableOpacity>
</LinearGradient>
</View>
</View>
</>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: "#0A5640",
},
scrollContainer: {
height: "100%",
},
image: {
width,
height: "100%",
},
btnAuth: {
fontSize: 18,
fontWeight: "bold",
paddingHorizontal: 60,
paddingVertical: 10,
color: "#fff",
marginLeft: 10,
},
btn: {
color: "#fff",
marginTop: 70,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-around",
alignContent: "space-between",
zIndex: 200,
paddingRight: 10,
paddingLeft: 10,
bottom: 3,
position: "absolute",
},
});
Did you mean the space between SignIn and SignUp button? You can use flex or width to define the touchableOpacity width. Is this something that you tried to achieve?
import * as React from 'react';
import {Text,View,StyleSheet,TouchableOpacity,}from 'react-native';
export default function App() { return (
<View style={styles.container}>
<View style={styles.btn}>
<TouchableOpacity style={styles.btnAuth}>
<Text style={{color:'#000', fontSize:18}}>Sign In</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btnAuth}>
<Text style={{color:'#000', fontSize:18}}>Sign Up</Text>
</TouchableOpacity>
</View>
</View> ); }
const styles = StyleSheet.create({ container: { backgroundColor: '#0A5640', flex:1 }, btnAuth: {
padding: 20,
width : '45%',
alignItems:'center',
backgroundColor:'yellow' }, btn: {
color: '#fff',
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
bottom: 3,
position: 'absolute', }, });

The image displayed in marker callout is cut

In my app, I want to display callout on a user clicks on the marker. I read that there are problems with displaying images in callout and a lot of people suggest placing the image in <Text> component [1,2,3]. For smaller images/icons this solution works, but I want to display one more "bigger" image, and here is an effect:
I don't know why this image has this "top margin" and why it is cut in the half. I was trying a lot of changes in the style of this Image and it's resizeMode but nothing is working. My other images in callout - like this icon on the bottom - had the same problem but adding a bigger size to the component in which there are placed help and everything looks fine. I was trying this solution on this big top image but it isn't working.
I will be grateful for any help and suggestions.
He is the Callout component code:
import { Dimensions, Image, StyleSheet, Text, View } from 'react-native'
import React, { Component } from 'react'
import { FontAwesome } from '#expo/vector-icons'
import PropTypes from 'prop-types'
import { colors } from '../constants/Colors'
const { width, height } = Dimensions.get('screen')
function getSpotDifficulty(spot) {
switch (spot.difficulty) {
case 0:
return 'DLA KAŻDEGO'
case 1:
return 'UMIARKOWANA'
case 2:
return 'DUŻA'
case 3:
return 'TYLKO DLA PROSÓW'
default:
return ' - '
}
}
function getSpotPopularity(spot) {
switch (spot.popularity) {
case 0:
return 'MALE'
case 1:
return 'SREDNIE'
case 2:
return 'DUŻE'
default:
return ' - '
}
}
const WATER_TYPE_FLAT_IC = require('../assets/images/ic_flat.png')
const WATER_TYPE_WAVE_IC = require('../assets/images/ic_wave.png')
const DIFFICULTY_EASY_IC = require('../assets/images/ic_flag_white_24.png')
const DIFFICULTY_HARD_IC = require('../assets/images/ic_flag_red_24.png')
export default class SpotMarkerCallout extends Component {
render() {
const marker = this.props.marker
const waterTypeIcon = marker.waterType === 0 ? WATER_TYPE_FLAT_IC : WATER_TYPE_WAVE_IC
const difficultyIcon = marker.waterType === 0 ? DIFFICULTY_EASY_IC : DIFFICULTY_HARD_IC
return (
<View style={styles.markerCallout}>
<Text >
<Image style={{flex: 1, height: 200}}
resizeMode={'cover'}
source={require('../assets/images/example_spot_photo.jpg')}/>
</Text>
<View style={{ flex: 1, flexDirection: 'column', justifyContent: 'center' }}>
<View style={styles.markerHeader}>
<Text style={styles.spotNameText}>
{marker.name}
</Text>
<View style={{ flex: 1, justifyContent: 'space-between' }}>
<View style={styles.sportsIconsContainer}>
<View style={styles.singleInfo}>
<Text style={styles.textViewForIcon}>
<Image style={styles.sportIcon}
source={marker.windsurfing ? require('../assets/images/windsurfing_icon.png') : null}/>
</Text>
</View>
<Text style={styles.textViewForIcon}>
<Image style={styles.sportIcon}
source={marker.kitesurfing ? require('../assets/images/kitesurfing_icon.png') : null}/>
</Text>
<Text style={styles.textViewForIcon}>
<Image style={styles.sportIcon}
source={marker.surfing ? require('../assets/images/surfing_icon.png') : null}/>
</Text>
</View>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'flex-end' }}>
<View style={[styles.singleInfo, { marginRight: 8 }]}>
<FontAwesome name="star" color={colors.ratingColor} size={10}/>
<Text style={{ marginRight: 4, color: colors.ratingColor }}>{marker.rating}</Text>
</View>
<View style={[styles.singleInfo, { marginRight: 8 }]}>
<FontAwesome name="location-arrow" color={colors.secondaryColor} size={10}/>
<Text style={{ marginRight: 4, color: colors.secondaryColor }}>{marker.distance} km</Text>
</View>
</View>
</View>
</View>
<Text style={styles.descriptionText} numberOfLines={3} ellipsizeMode='tail'>
{marker.description}
</Text>
</View>
<View style={{ flex: 1, flexDirection: 'row', marginVertical: 8 }}>
<View style={{ flex: 1, flexDirection: 'column', marginLeft: 4, }}>
<View style={styles.singleInfo}>
<Text style={styles.infoIconTextView}>
<Image style={styles.infoIcon} source={waterTypeIcon}/>
</Text>
<Text style={styles.infoText}>{marker.waterType === 0 ? 'FLAT' : 'WAVE'}</Text>
</View>
<View style={styles.singleInfo}>
<Text style={styles.infoIconTextView}>
<Image style={styles.infoIcon} source={require('../assets/images/ic_shaka_128.png')}/>
</Text>
<Text style={styles.infoText}>{marker.schools ? ' SZKOLENIA DOSTĘPNE' : 'BRAK SZKOLEN'}</Text>
</View>
</View>
<View style={{ flex: 1, flexDirection: 'column', marginLeft: 16, }}>
<View style={styles.singleInfo}>
<Text style={styles.infoIconTextView}>
<Image style={styles.infoIcon} source={difficultyIcon}/>
</Text>
<Text style={styles.infoText}>{getSpotDifficulty(marker)}</Text>
</View>
<View style={styles.singleInfo}>
<Text style={styles.infoIconTextView}>
<Image style={styles.infoIcon} source={require('../assets/images/ic_peoples.png')}/>
</Text>
<Text style={styles.infoText}>{getSpotPopularity(marker)}</Text>
</View>
</View>
</View>
</View>
)
}
}
SpotMarkerCallout.propTypes = {
marker: PropTypes.object.isRequired,
}
const styles = StyleSheet.create({
markerCallout: {
flex: 1,
width: width * 0.8,
flexDirection: 'column',
paddingLeft: 12,
justifyContent: 'space-around',
},
markerHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
},
spotNameText: {
fontSize: 22,
fontFamily: 'dosis_light',
textTransform: 'uppercase',
alignSelf: 'center',
},
sportsIconsContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginRight: 8,
},
singleInfo: {
flexDirection: 'row',
alignItems: 'center',
},
infoIcon: {
height: 18,
width: 18,
justifyContent: 'center',
alignItems: 'center',
},
infoIconTextView: {
height: 24,
justifyContent: 'center',
alignItems: 'center',
},
descriptionText: {
fontSize: 12,
color: colors.textBlackSecondaryColor,
paddingTop: 5,
},
sportIcon: {
height: 24,
width: 24,
},
textViewForIcon: {
height: 32,
},
infoText: {
fontSize: 10,
paddingLeft: 8,
justifyContent: 'center',
alignSelf: 'center',
},
})
And here is the code of usage:
<MapView.Callout onPress={() => this.props.navigation.navigate('SpotInfo', { chosenSpot: spot })}>
<TouchableHighlight>
<SpotMarkerCallout
marker={spot}/>
</TouchableHighlight>
</MapView.Callout>
</Marker>
i have notices you are using component change that to view
like
const newWidth = Dimensions.get('window').width
<View style={{ width: newWidth * 0.18, height: newWidth * 0.18 }}>
<Image style={{ width: newWidth * 0.18, height: newWidth * 0.18 }} source={require('your image path')} />
</View>
newWidth * 0.18 is the 18% width is the screen, change 0.18 to your desired percentage

Why is my modal height taking up half of the screen?

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>

Align 3 dynamic views in one row

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,
}
});