React-Native: Margin with percentage value - css

I'm trying to use percentage value for margin style attribute on my React Native project but it seems to reduce the height of one of my View component. If I replace percentage value by an absolute value, there is no more issue and it works fine. Did you try to use percentage value as margin in React Native ? Here is a little sample of code to reproduce this issue:
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.scene}>
<View style={styles.card}>
<View style={styles.container}>
<Text>Hello World</Text>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
scene: {
backgroundColor: '#F9E8D5',
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'column'
},
card: {
backgroundColor: '#E6D5C3',
flex: 0.2,
flexDirection: 'column',
marginTop: '20%' // Replace by 20
},
container: {
backgroundColor: '#FFFFFF',
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
}
});
Thank you very much !

A component's height and width determine its size on the screen.
The simplest way to set the dimensions of a component is by adding a fixed width and height to style. All dimensions in React Native are unitless, and represent density-independent pixels.
Setting dimensions this way is common for components that should always render at exactly the same size, regardless of screen dimensions.
Use flex in a component's style to have the component expand and shrink dynamically based on available space. Normally you will use flex: 1.
The following references will be use for styling
https://facebook.github.io/react-native/docs/height-and-width.html
https://medium.com/the-react-native-log/tips-for-styling-your-react-native-apps-3f61608655eb
https://facebook.github.io/react-native/docs/layout-props.html#paddingtop
Use Dimensions to calculate to get the height and width of the screen.
var {height, width} = Dimensions.get('window');
To specify percentage by getting the screen size and convert it into percentage.
Sample example:
const { height } = Dimensions.get('window');
paddingTop: height * 0.1 // 10 percentage of the screen height

This is a real bug but Facebook does not care.
https://github.com/facebook/react-native/issues/19164

Related

React-Native: Scroll view does not respect justify content?

When attempting to use ScrollView it appears to not respect justifyContent of its parent container.
import React from 'react';
import { Text, ScrollView, StyleSheet, TextStyle, View, ViewStyle } from 'react-native';
interface TODO_TextCard {
text: string,
}
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
<ScrollView>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
</View>;
}
const styles = StyleSheet.create({
quoteTextStyle: {
fontSize: 30,
fontStyle: 'italic'
} as TextStyle,
viewStyle: {
flex: 1,
borderWidth: 2, borderColor: 'red',
justifyContent: 'center',
paddingHorizontal: 10
} as ViewStyle,
});
<TODO_TextCard text={'The mind adapts and converts to its own purposes the obstacle to our acting. The impediment to action advances action. What stands in the way becomes the way'}/>
Rendered as:
Now if I remove the and just render text such as
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</View>;
}
The Text element does respect the justifyContent:center of the parent and renders as:
Is it possible for Scroll view to be centered?
The solution that I have in mind right now is to check the length of the text and conditionally render Scroll View something like:
/** This some text length would have to be different depending on the device screen, and
* even with different device screens would still not work all the time if the text
* can have new lines in it.*/
const SOME_TEXT_LENGTH = 300;
export const TODO_TextCard: React.FunctionComponent<TODO_TextCard> = (props: TODO_TextCard) => {
return <View style={styles.viewStyle}>
{props.text.length > SOME_TEXT_LENGTH ?
<ScrollView>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
:
<Text style={styles.quoteTextStyle}>{props.text}</Text>
}
</View>;
}
Which very much is not ideal, due to different device screens as well as text potentially having new lines.
The ScrollView does in fact respect the justifyContent:center of its parent. The ScrollView is placed in the center of the outer View component. But here the ScrollView takes up the whole vertical screen, so it seems like it is not centered.
Try setting <ScrollView style={{backgroundColor: 'green'}}> to see what i mean.
Try applying viewStyle or a similar styling to the ScrollView itself. Make sure that you use the attribute contentContainerStyle instead of style. This snippet works for me.
<View style={styles.viewStyle}>
<ScrollView contentContainerStyle={{flex: 1, justifyContent: 'center'}}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
</View>
I also found this article. Maybe it will also help you out.
You need to give styling to ScrollView, for styling ScrollView you can use style or contentContainerStyle prop:
style defines the outer container of the ScrollView, e.g its height and relations to siblings elements
contentContainerStyle defines the inner container of it, e.g items alignments, padding, etc
In your case you need to give contentContainerStyle to position your items for eg:
return (
<View style={styles.viewStyle}>
{props.text.length > SOME_TEXT_LENGTH ?
<ScrollView
contentContainerStyle={{
flex: 1, //To take full screen height
justifyContent: 'center',
alignItems: 'center,
}}>
<Text style={styles.quoteTextStyle}>{props.text}</Text>
</ScrollView>
:
<Text style={styles.quoteTextStyle}>{props.text}</Text>
}
</View>
);

How do i dynamically resize buttons in a row based off the number of buttons in a row in React Native

I'm currently trying to dynamically display different rows of buttons that are evenly spaced out from each other. In my code, two rows have five buttons each, and the third row has only two buttons. Since both buttons are being created using the same component, I was wondering if there was any CSS to help me do this properly.
Currently, here is the code for my the button component:
const NodesOptionButton = (props) => {
const styles = StyleSheet.create({
bold: {
fontWeight: '800',
},
textWrapper: {
width: 60,
height: 60,
borderWidth: 1,
borderStyle: 'solid',
borderColor: '#000',
padding: 12,
marginVertical: 8,
backgroundColor: props.isActive ? '#000' : '#fff',
alignItems: 'center',
justifyContent: 'center',
},
activeTextColor: {
color: '#fff',
}
});
And I'm rendering the three rows of button through this code:
const NPage = (props) => {
const styles = StyleSheet.create({
nodeOptionsContainer: {
flexDirection:'row',
backgroundColor:'red',
display: 'flex',
justifyContent: 'space-evenly',
},
});
//lots of code with logic
return (
<React.Fragment>
<View style={styles.nodeOptionsContainer}>
{nodeNumberOptions}
</View>
<View style={styles.nodeOptionsContainer}>
{clincallyOccultOptions}
</View>
<View style={styles.nodeOptionsContainer}>
{MSIOptions}
</View>
</React.Fragment>
)
Is there any suggestions, or would I have to create a new component for that specific button? Thanks!
You want the two last buttons to take up the whole row? You can always try to add:
flex-grow: 1
to your button component.
If you want your buttons to always take up the whole row, you should just need to add flex: 1 to your Button component root View, and you don't need space-evenly in the parent.
If that's not the case, maybe you should post a pic of the desired design and the current design with problem. It helps understand.
p.s: another tip for performance...define your style outside your component.

Flexbox doesn't work when flexDirection is set to "row"

I'm playing around with Flexbox, but I can't seem to figure out why FlexDirection doesn't work when set to 'row'.
export default function WorkoutScreen() {
return (
<SafeAreaView style={styles.container}>
<AppText>Heading</AppText>
<View style={styles.sets}>
<AppText>Reps</AppText>
<FontAwesome name="minus-square" size={48} color="purple" />
<AppText>9</AppText>
<FontAwesome name="plus-square" size={48} color="pink" />
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
sets: {
flex: 1,
**flexDirection: "row",**
justifyContent: "space-between",
alignItems: "center",
marginTop: 100,
},
});
I've been scratching my head about what I'm doing wrong, any tip to fix this would be greatly appreciated! I'm trying an ios simulator on Iphone pro 12 max.
OK I finally figured this out. If you check the [Text documentation][1], it says
The element is unique relative to layout: everything inside is
no longer using the Flexbox layout but using text layout. This means
that elements inside of a are no longer rectangles, but wrap
when they see the end of the line.
So basically I had to wrap the texts inside View tags.
[1]: https://reactnative.dev/docs/text

How to use percentage padding top and bottom in React Native?

I am trying to achieve dynamic padding top and bottom. I am aware that paddingTop and paddingBottom with % will use the width of the container and I am fine with that.
Unfortunately when I do set the paddingTop to any value with %, it sets the paddingBottom to the same value. Basically paddingTop: '5%', paddingBottom: '0%' will give me equal 5% paddings on both sides.
If I set paddingBottom to any % value - it's just being added to the value that came form the top. So: paddingTop: '5%', paddingBottom: '10%' results in paddingBottom equal to 15%...
I checked the same solution in a web project and there it works as expected.
The snack presenting the problem:
https://snack.expo.io/BJ9-2t8LB
The problem is on both Android and iOS.
How to solve it?
Apply the value to the child container to be applied, not to the parent container.
I have modified the answer according to the conditions you want. You should send Bottom's territory to the parent's container. Because they interact with each other in their child's container, they must be independent.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.wrapper}>
<View style={styles.inner}>
<View style={{ backgroundColor: 'yellow' }}>
<Text>TOP</Text>
</View>
</View>
<View style={{ backgroundColor: 'red', }}><Text>BOTTOM</Text></View>
</View>
);
}
}
const styles = StyleSheet.create({
wrapper: {
flex:1,
paddingLeft: 24,
paddingRight: 24,
backgroundColor: 'green',
paddingBottom:"5%"
},
inner: {
flex:1,
justifyContent: 'space-between',
backgroundColor: 'blue',
marginTop:"10%"
},
});
That is strange behavior, you should bring it up as an issue to react-native.
In the meantime, a workaround would be applying marginTop and marginBottom to the inner View, instead of paddingTop and paddingBottom to the wrapper View.
const styles = StyleSheet.create({
ayz:{
marginTop:"15%",
backgroundColor:'pink',
alignItems:'center',
justifyContent:'center',
},
asd:{
color:'white',
fontSize:50,
fontWeight:'bold'
}
});

Center items with aspect ratio in FlatList - React Native

This seems like an easy question at first but it's actually tricky.
Better to go directly to the example. I've created a snack with the sample code here https://snack.expo.io/BkSNtNrWV
I want to have a list of items with given aspect ratio (say 3:2) and the items should take as much space as possible with a maximum limit on size. This sample code does it:
<View>
<FlatList style={{backgroundColor:'lightgray'}}
data={[{key: 'a'},{key: 'b'}]}
renderItem={({item}) =>
<View style ={styles.pink}></View>
}/>
</View>
const styles = StyleSheet.create({
pink: {
backgroundColor: "#A37E93",
maxHeight: 150,
aspectRatio: 3/2,
borderWidth: 1,
}});
And this is the result:
However, the problem is that I would like to have the items aligned to the center. I tried to wrap the list item in a flexbox with 'row' direction but that caused the item to have 0 height => not displayed. Justify content didn't help either (it's possible that I do it incorrectly).
Does anyone know how to solve this please?
Updated the code. Add flex to inner item and wrap the view inside another with screen width.
import * as React from 'react';
import { Text, View, StyleSheet,FlatList,Dimensions } from 'react-native';
import { Constants } from 'expo';
const{width} = Dimensions.get('window')
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View>
<FlatList style={{backgroundColor:'lightgray'}}
data={[{key: 'a'},{key: 'b'}]}
renderItem={({item}) =>
<View style={styles.item}>
<View style ={styles.pink}></View>
</View>
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
item:{
width:width,
height:150,
alignItems:'center'
},
pink: {
flex:1,
backgroundColor: "#A37E93",
maxHeight:150,
aspectRatio:3/2,
borderWidth:1,
}
});

Resources