ScrollView with flex 1 makes it un-scrollable - flexbox

I'm trying to run flex on a ScrollView, and as long as the ScrollView has flex: 1 the scroll inside does not work.
here is the expo fiddle (that you can run this code and play with)
https://snack.expo.io/SySerKNp-
note that if you remove the flex: 1 from the ScrollView it does let scroll but then you lose the flex power ( the ability to let the red container down to push up the upper box (the ScrollView) ) so I must have a flex there.
p.s - I'm working only on android, and I haven't tested it on iPhone( I don't mind the result there )
any idea what am I missing ? why the ScrollView won't function right when it has a flex: 1 ?
thanks !

Try using flexGrow: 1 instead of flex: 1 in scrollView content container style as follows.
<ScrollView contentContainerStyle={{ flexGrow: 1, borderColor: 'green', borderWidth: 5 }}>
<View style={styles.box1} />
<View style={styles.box2} />
<View style={styles.box1} />
</ScrollView>
https://snack.expo.io/HkkEVoh6Z

I believe your problem is that you are telling the ScrollView to occupy all available space with flex=1 but the thing is that ScrollView works differently. It automatically renders all its children so it does work different with flex. That is the difference against a normal ListView or FlatList which have better performance.
I believe this snack solves that issue: https://snack.expo.io/SkxN9GOT-
Basically, I am getting the height of the device and setting the ScrollView with a fixed height, based on (screenHeight - the current height of the red box).

The best thing to do is to wrap your ScrollView in a View and control that view with flex, your scroll view will follow.
This is a little example
<View style={{flex: 1, flexDirection: 'column',}}>
<View style={{flex:5, backgroundColor : 'green' }}>
<ScrollView style={{margin:50, backgroundColor : 'pink' }}>
<Text> Hello Scroll View </Text>
<Text> Hello Scroll View </Text>
<Text> Hello Scroll View </Text>
<Text> Hello Scroll View </Text>
<Text> Hello Scroll View </Text>
<Text> Hello Scroll View </Text>
</ScrollView>
</View>
<View style={{flex:1, backgroundColor : 'blue' }}>
<Text> Hello Static View </Text>
</View>
</View>

This answer has already been provided how to do it.
But here's an explanation why you cannot do by your method. The styles given in contentContainerStyle is
applied to the scroll view content container which wraps all of the child views.
So when you apply flex: 1 to contentContainer it takes full height of ScrollView whose height is also flex: 1 as its parent View.
You can also simulate -
the ability to let the red container down to push up the upper box
by adding a parent to ScrollView and apply style in the parent
<View style={styles.root}>
<View style={{ flex: 1, borderColor: 'green', borderWidth: 5 }}>
<ScrollView>
<View style={styles.box1} />
<View style={styles.box2} />
<View style={styles.box1} />
</ScrollView>
</View>
<View style={{ height: this.state.height, backgroundColor: 'red' }}>
<TouchableOpacity onPress={() => this.setState({ height: this.state.height + 10 })}>
<Text>Click</Text>
</TouchableOpacity>
</View>
</View>

Try this one it will 100% solve your problem
import React, { Component } from 'react';
import { AppRegistry, View,ScrollView } from 'react-native';
export default class AlignItemsBasics extends Component {
render() {
return (
// Try setting `alignItems` to 'flex-start'
// Try setting `justifyContent` to `flex-end`.
// Try setting `flexDirection` to `row`.
<View style={{ flex: 1,flexDirection: 'column' }}>
<View style={{ height: 50, backgroundColor: 'powderblue'}} />
<View style={{ flex: 1, backgroundColor: 'skyblue'}} >
<ScrollView>
<View style={{ flexDirection: 'column' , minHeight: 'fit-content'}} >
<View style={{ height:150, backgroundColor: 'red'}} />
<View style={{ minHeight: 'fit-content', backgroundColor: '#fe3222' }} />
<View style={{ height:150, backgroundColor: '#fff222'}} />
<View style={{ height:150, backgroundColor: '#555222'}} />
</View>
</ScrollView>
</View>
</View>
);
}
};
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);

Related

React native display layout

Please can you help me? Im trying to do layout like this, from begining there will be camera but if I click button driving info it will be replaced with that, here is the layout I want and here is my code. Right now all the touchablehighlits(buttons) are overlaying, + camera window should be livestream from raspberry pi camera but right now Im focusing just on layout.
const MainScreen = () => {
return(
<View>
<View style={{flex: 33, flexDirection: 'row', justifyContent: 'flex-start', position: 'relative'}}>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}> CAMERA </Text>
</TouchableHighlight>
</View>
<View style={{flex: 33, flexDirection: 'row', justifyContent: 'center', position: 'relative'}}>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}> Lane assistant </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}> disconnect </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}> driving info </Text>
</TouchableHighlight>
</View>
<View style={{flex: 33, flexDirection: 'row', justifyContent: 'flex-end', position: 'relative'}}>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}>- </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}> cruise control </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} >
<Text style={styles.txt}>+ </Text>
</TouchableHighlight>
</View>
</View>
);
}
const styles = StyleSheet.create({
button:{
justifyContent: 'space-between',
},
txt:{
fontSize: 30,
}
});
This should be fine:
export default function App() {
return (
<View style={{flex: 1}}>
<View style={styles.topContainer}>
<TouchableHighlight >
<Text> CAMERA </Text>
</TouchableHighlight>
</View>
<View style={{flex: 1}}>
<View style={styles.buttonRowContainer}>
<TouchableHighlight style={styles.touchableContainer} >
<Text > Lane assistant </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.touchableContainer} >
<Text>disconnect </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.touchableContainer} >
<Text > driving info </Text>
</TouchableHighlight>
</View>
<View style={styles.buttonRowContainer}>
<TouchableHighlight style={styles.touchableContainer} >
<Text >- </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.touchableContainer} >
<Text > cruise control </Text>
</TouchableHighlight>
<TouchableHighlight style={styles.touchableContainer} >
<Text >+ </Text>
</TouchableHighlight>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
buttonRowContainer: {
flex: 1, flexDirection: 'row'
},
touchableContainer: {
flex: 1, justifyContent: 'center', alignItems: 'center'
},
topContainer: {
flex: 1, justifyContent: 'center', alignItems: 'center'
}
})
I'm going to explain how flex works. If you only have one element with flex: 1 it will take all the screen space. This is usually done when you have a View which will contain all the other elements. If we want to divide the screen by two, we have to define 2 components with flex: 1
- Main -> flex: 1
- Children 1 -> flex: 1
- Children 2 -> flex: 1
Children 1 will take 50% of the screen size as well as Children 2. If we want children 1 to take 66% of the screen we simply add flex: 2. Is like telling React "hey, I want you to divide the screen in 3 equal parts, Children 1 takes 2 portions of the screen when Children 2 only takes 1". Remember this will only work if your parent has set flex.

How to use ScrollView with third party Components in React Native?

Very simple, how can I use ScrollView when using an third party (react-native-elements) List/List-Items? The given docs does not inform this: link
The list is fully working, but can't be scrolled:
Here is the code for rendering the list:
<View style={{ flex: 1 }}>
<List>
{
list.map((l, i) => (
<ListItem
roundAvatar
key={i}
title={l.name}
subtitle={
<View>
<View style={styles.subtitleView}>
<Text style={styles.ratingText}>{l.subtitle}</Text>
</View>
</View>
}
avatar={<Avatar
medium
rounded
source={l.avatar_url && { uri: l.avatar_url }}
title={l.name[0]}
/>}
/>
))
}
</List>
</View>
If I simply change the View to ScrollView, that should be the obvious move, I get this error:
I'm importing ScrollView from native-base and the List from react-native-elements.
Try to make the ScrollView under your View, also add additional View (not required) under the ScrollView.
<View style={{ flex: 1 }}>
<ScrollView>
<View>
<List>
{
list.map((l, i) => (
<ListItem
roundAvatar
key={i}
title={l.name}
subtitle={
<View>
<View style={styles.subtitleView}>
<Text style={styles.ratingText}>{l.subtitle}</Text>
</View>
</View>
}
avatar={<Avatar
medium
rounded
source={l.avatar_url && { uri: l.avatar_url }}
title={l.name[0]}
/>}
/>
))
}
</List>
</View>
</ScrollView>
</View>
Also consider using FlatList rather than ScrollView for better performance.
Reference:
https://facebook.github.io/react-native/docs/scrollview
https://facebook.github.io/react-native/docs/flatlist

Text vertical align in react native (using nativebase)

I was wondering there is a way I can align vertically in React Native. I'm trying to position on the bottom but I don't think I can find a good way to do it.
If anyone knows how to solve this issue, please let me know.
You can use the flex property, justifyContent to achieve this. Full documentation here.
<View style={{justifyContent: 'center'}}>
<Text>Vertically Centered Text</Text>
</View>
to align any content including text both horizontally and vertically, simply use the following in the container which holds it
container :{
justifyContent: 'center', //Centered horizontally
alignItems: 'center', //Centered vertically
flex:1
}
You can use an android-only style property textAlignVertical
To align text on top:
style={{textAlignVertical: 'top'}}
To align text on center:
style={{textAlignVertical: 'center'}}
To align text on bottom:
style={{textAlignVertical: 'bottom'}}
This problems occurs especially when you are using image or icon. I had a same problem my solution:
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }}>
<Icon type="MaterialCommunityIcons" name="barcode" />
<Text style={{ textAlign: 'center' }}>{urun_data.barkod}</Text>
</View>
I had a similar problem and looked at many of the other posts here. Here is what worked for me.
I created an initial view, and nested the elements I wanted vertically centered within that view. I made the mistake of including 'flex: 1' in the initial view, which screwed up the vertical alignment.
The code:
<View style={{flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}>
<Text>Content here to be vertically aligned</Text>
<Switch>...</Switch>
</View>
RN version >= 0.55.2 is support to "textAlignVertical" now.
<TextInput
style={styles.text}
onChangeText={text => console.log('text >>>>>>>', text)}
value='sample text'
/>
text: {
textAlign: 'center',
textAlignVertical: 'center',
}
Working with both cases flex: 1 and set height of the <Text> component.
Text vertical center alignment summary
Case 1: There is only one Text under View
Ios: Use flex with alignItems/justifyContent to be more centered,
Adr: height = lineHeight, includeFontPadding: false more centered
Case 2: There are two Texts in a line view and the two Text fonts are different, and the Text with a smaller font size does not need to use the height.
The larger one is aligned using the above method. The smaller one can only be used with font-size, but not with the line-height and height attributes. In this case, both texts can be centered.
Case 3: There are two Texts in a line view and the two Text fonts are different, and the Text with a smaller font size must use the height.
The one with the larger font size is aligned using the above method, and the smaller font size uses height with padding and includeFontPadding to achieve alignment.
And Demo
<View
style={{
flexDirection: 'row',
height: 38,
borderWidth: 1,
borderColor: '#000',
alignItems: 'center'
}}
>
<Text
style={{
fontSize: 24
}}
>
测试
</Text>
<Text
style={{
fontSize: 24,
lineHeight: 36,
height: 36,
includeFontPadding: false
}}
>
测试
</Text>
</View>
<View
style={{
flexDirection: 'row',
height: 38,
borderWidth: 1,
borderColor: '#000',
alignItems: 'center'
}}
>
<Text
style={{
fontSize: 24
}}
>
ios设备
</Text>
<Text
style={{
fontSize: 16
}}
>
更对齐
</Text>
</View>
<View
style={{
flexDirection: 'row',
height: 38,
borderWidth: 1,
borderColor: '#000',
alignItems: 'center'
}}
>
<Text
style={{
fontSize: 24,
lineHeight: 36,
height: 36,
includeFontPadding: false
}}
>
安卓
</Text>
<Text
style={{
fontSize: 12,
height: 18,
includeFontPadding: false,
paddingVertical: 2,
paddingHorizontal: 1,
paddingTop: DeviceInfo.isIOS ? 3 : 2,
}}
>
更对齐
</Text>
</View>
The flex: 1 makes the child view take up all the remaining space in the parent view. So remember to make sure the parent is occupying the space it is supposed to.
I would advocate wrapping your content in a <SafeAreaView> tag so that is adjusts content to the device it is in. But you could use any other view type.
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Centered Text</Text>
</SafeAreaView>
flex: 1 makes the view take up the full width and heigh of the view its in
justifyContent: 'center' vertically centers the children
alignItems: 'center' horizontally centers the children
You can also use textAlign: center on the Text element and remove the alignItems: 'center'. This of course would only center the text in the Text object and wouldn't work if you had multiple elements that needed to be centered.
You can use flexbox with justifyContent: 'flex-end' to achieve vertical centering.
Here's a snack: https://snack.expo.io/#rynek/vertical-centering-with-flexbox-in-react-native
Here's a somewhat ugly solution to the problem. The ScrollView will take up the remaining vertical space, pushing the text down to the bottom.
<View>
<ScrollView>{}</ScrollView>
<Text>Your text</Text>
</View>
Or..
<View>
<View style={{ flex: 1 }}>{}</View>
<Text>Your text</Text>
</View>
use flex:1 property on both as on container of the Text component and itself inside the Text component.Because if u don't define the height and width its not working.
<View style={{
flex:1,
}} >
<Text style={{
flex:1,
color: COLORS.primary,
fontFamily: "FredokaOne-Regular",
fontSize:40,
textAlign:"center",
textAlignVertical:"center",
}}
numberOfLines={2} >
Travia War
</Text>
</View>
Simply use the alignItems for the vertical alignment
alignItems: 'flex-start' //for start the View : vertical-align: top
alignItems: 'flex-end' // for vertical-align: bottom
alignItems: 'center' // for vertical-align: middle
<View style={{ flexDirection: 'row', alignItems: 'flex-start'}}>
<View> <Text>hello 1</Text> </View>
<View> <Text>hello 2</Text> </View>
</View>
Check this example with changing of alignItems

How can I set my view to take top half of the screen for react-native android app?

I want to set my <View> to take only the top half of the screen. If I set flex:1 on the view's style, it will take the full screen. See below code:
render(){
return(
<View style={{flex:1}}>
...
</View>
);
}
I have tried to set the flex value to 0.5 but it doesn't help. How can I set my view takes half of the screen on flexbox?
render(){
return(
<View style={{flex:1}}>
<View style={{flex:.5}}>
...
</View>
<View style={{flex:.5}}/>
</View>
);
}
try this code:
<View style={{flex: 1,flexDirection:'row'}}>
<View style={{flex: 2, backgroundColor: 'powderblue',height:100}} />
<View style={{flex: 2, backgroundColor: 'skyblue',height:100}} />
</View>
Try this:
import {Dimensions, StyleSheet, View} from 'react-native';
const height = Dimensions.get('window').height*0.5;
const width = Dimensions.get('window').width;
const styles = StyleSheet.create({
container: {
width,
height
}
)};
render(){
return(
<View style={styles.container}>
...
</View>
);
}
Another way is you can use the Dimensions API to check the Height of the device and set the component height to half and position absolute: Dimensions

Style part of a text component

I am trying to make react native components where different words in the same component have different styling.
For example I have buttons with name and subtitle on the button, I want the subtitle text to be smaller.
<Text style={styles.buttonText}>{speciesArry[i].title} {"\n"} {speciesArry[i].subtitle}</Text>
I need to wrap the subtitle in its own component so that I can style it?
A second example
I have another button with the text component
Green - best Choice
I need the the word "green" to be green.
For the first question, a button with a title and a subtitle, you can wrap a view in a TouchableHighlight and then place multiple Text elements to create a title and a subtitle:
<TouchableHighlight style={{height:70, backgroundColor: 'blue'}}>
<View style={{flexDirection: 'column', }}>
<Text style={{textAlign:'center', color: 'white', fontSize:22, marginTop:10}}>MAIN TEXT</Text>
<Text style={{textAlign:'center', color: 'white', fontSize:14}}>Subtitle</Text>
</View>
</TouchableHighlight>
For the second question, having different styling within a single text component, you need to wrap text components within text components, the way you might do with a span in html:
<Text style={styles.mainStyle}>This text is red, <Text style={styles.blacktext}>this text is black, </Text><Text style={styles.boldgreen}>this text is bold and green!</Text></Text>
And the button example you provided above would look something like this:
<TouchableHighlight style={{height:70, backgroundColor: 'orange'}}>
<View style={{ flexDirection: 'row', justifyContent:'center'}}>
<Text style={{fontSize:18, marginTop: 22}}><Text style={{color: 'green'}}>Green</Text> - best Choice</Text>
</View>
</TouchableHighlight>
For the float:right question: There is no anything exactly like it in flexbox, but there is something very similar to it called: justifyContent: 'flex-end'. Below is how that would look, and I've updated the origin project to reflect the below code:
<View style={{flexDirection: 'row', justifyContent: 'flex-end'}}>
<Text>Floating right</Text>
</View>
I've set up a full working project with the above examples here, and pasted the entire code for the project below as well. Hope this helps!
https://rnplay.org/apps/KqE-cA
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
} = React;
var SampleApp = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={{marginTop:70}}>
<TouchableHighlight style={{height:70, backgroundColor: 'blue'}}>
<View style={{flexDirection: 'column', }}>
<Text style={{textAlign:'center', color: 'white', fontSize:22, marginTop:10}}>MAIN TEXT</Text>
<Text style={{textAlign:'center', color: 'white', fontSize:14}}>Subtitle</Text>
</View>
</TouchableHighlight>
</View>
<View style={{marginTop:20}}>
<Text style={styles.mainStyle}>This text is red, <Text style={styles.blacktext}>this text is black, </Text><Text style={styles.boldgreen}>this text is bold and green!</Text></Text>
</View>
<View style={{marginTop:20}}>
<TouchableHighlight style={{height:70, backgroundColor: 'orange'}}>
<View style={{ flexDirection: 'row', justifyContent:'center'}}>
<Text style={{fontSize:18, marginTop: 22}}><Text style={{color: 'green'}}>Green</Text> - best Choice</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
},
mainStyle: {
color: 'red'
},
blacktext: {
color: 'black'
},
boldgreen: {
color: 'green',
fontWeight: 'bold'
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);

Resources