React native flex box not using all available space - android

I have a layout that I want to make full screen. This is how it looks right now:
What I want is for the layout to take up all the space on the screen (so the submit button should be way down at the bottom). I'm trying to use {flex: 1} but it's not working. Here's the code:
'use strict';
const React = require('react-native');
const {
StyleSheet,
Text,
View,
BackAndroid,
TextInput,
TouchableNativeFeedback,
ScrollView
} = React;
const ActionButton = require('./action-button');
module.exports = React.createClass({
handleBackButtonPress () {
if (this.props.navigator) {
this.props.navigator.pop();
return true;
}
return false;
},
componentWillMount () {
BackAndroid.addEventListener('hardwareBackPress', this.handleBackButtonPress);
},
componentWillUnmount () {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButtonPress);
},
onInputFocus (refName) {
setTimeout(() => {
let scrollResponder = this.refs.scrollView.getScrollResponder();
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
React.findNodeHandle(this.refs[refName]),
0,
true
);
}, 50);
},
render: function() {
return (
<ScrollView ref='scrollView' style={styles.scroller}>
<View style={styles.container}>
<View style={styles.header}>
<Text>New Post</Text>
<View style={styles.actions}>
<ActionButton handler={this.handleBackButtonPress} icon={'fontawesome|close'}
size={15} width={15} height={15} />
</View>
</View>
<View style={styles.content}>
<TextInput underlineColorAndroid={'white'}
placeholder={'Who\'s your professor?'}
ref='professor'
onFocus={this.onInputFocus.bind(this, 'professor')}
style={styles.professor}
/>
<TextInput multiline={true}
underlineColorAndroid={'white'}
placeholder={'What do you think?'}
ref='post'
onFocus={this.onInputFocus.bind(this, 'post')}
style={styles.post}
/>
</View>
<View style={styles.footer}>
<TouchableNativeFeedback
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={{width: 50, height: 25, backgroundColor: 'green'}}>
<Text>Submit</Text>
</View>
</TouchableNativeFeedback>
</View>
</View>
</ScrollView>
);
}
});
const styles = StyleSheet.create({
scroller: {
flex: 1,
flexDirection: 'column'
},
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
backgroundColor: 'white',
padding: 5,
},
post: {
flex: 3
},
professor: {
flex: 1
},
actions: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignSelf: 'center'
},
header: {
flex: 1,
padding: 5,
flexDirection: 'row'
},
content: {
flex: 4
},
footer: {
flex: 1
}
});
From what I can see, I'm setting the flex property all the way down the view hierarchy but that still isn't doing anything (at the top level is a Navigator with {flex: 1} as well). Any suggestions?

What you want is the contentContainerStyle prop of the ScrollView component. If you replace :
<ScrollView ref='scrollView' style={styles.scroller}>
with :
<ScrollView ref='scrollView' contentContainerStyle={styles.scroller}>
That will fix your problem.
As stated in the doc :
These styles will be applied to the scroll view content container which wraps all of the child views.
Hope it helps!

If the colors are accurate in the screenshot, your scrollview is taking up all the vertical space already but the container is not (container background color is white). This is illustrating how scrollviews work. They act as containers where flex can't really grow the children to fit the vertical space as it is potentially infinite. Instead the children are rendered at their natural height. http://devdocs.io/react_native/scrollview
try instead using a view that takes up the entire screen height.
<View style={styles.container}>
... components here ...
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between'
}
})

You need to set a flexDirection: 'row' property for the outermost container:
scroller: {
flex:1,
flexDirection: 'row'
}
I've set up a basic version of your app here. The rest of the code is pasted below for the full working example:
https://rnplay.org/apps/gjBqgw
'use strict';
var React = require('react-native');
var {
StyleSheet,
Text,
View,
BackAndroid,
TextInput,
TouchableNativeFeedback,
ScrollView,
AppRegistry,
TouchableHighlight
} = React;
var SampleApp = React.createClass({
render: function() {
return (
<ScrollView ref='scrollView' style={styles.scroller}>
<View style={styles.container}>
<View style={styles.header}>
<Text>New Post</Text>
<View style={styles.actions}>
<TouchableHighlight handler={this.handleBackButtonPress} icon={'fontawesome|close'}
size={15} width={15} height={15}>
<Text>Button Text</Text>
</TouchableHighlight>
</View>
</View>
<View style={styles.content}>
<Text>Hello from content</Text>
</View>
<View style={styles.footer}>
<TouchableHighlight>
<View style={{width: 50, height: 25, backgroundColor: 'green'}}>
<Text>Submit</Text>
</View>
</TouchableHighlight>
</View>
</View>
</ScrollView>
);
}
});
const styles = StyleSheet.create({
scroller: {
flex:1,
flexDirection: 'row'
},
container: {
flex: 1,
backgroundColor: 'white',
padding: 5,
},
post: {
flex: 3
},
professor: {
flex: 1
},
actions: {
flex: 1,
flexDirection: 'row',
alignSelf: 'center'
},
header: {
flex: 1,
padding: 5,
flexDirection: 'row'
},
content: {
flex: 4
},
footer: {
flex: 1,
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);

Related

justifyContent not applying in View React Native

For some reason in this view the justify Content tag does not apply in my view ? I have tried applying it in the modalScreen view but that does not work either. Any ideas ?
function BottomPopup() {
return (
<View style={styles.modalScreen}>
<View style={styles.topbar}>
<MaterialCommunityIcons name="arrow-left" size={24} color="black" />
<Text>Create Post</Text>
<MaterialCommunityIcons name="content-save" size={24} color="black" />
</View>
<View>
<Text>hey</Text>
<Text>hey</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
modalScreen: {
alignItems: "center",
},
topbar: {
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
},
});
import { Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');
const styles = StyleSheet.create({
modalScreen: {
flex:1,
alignItems: "center",
backgroundColor: "yellow",
},
topbar: {
width: width,
flexDirection: "row",
justifyContent: "space-around",
backgroundColor: "green",
},
});
Add flex:1 in modalScreen style like Snack.IO
I had to add width: "100%" and then it worked

KeyBoardAvoidingView hides content

enter image description here
Current Behaviour
The KeyBoardAvoidingView hides the Login button.
Its the same on Android and on iPhone.
On an Android Tablet It hides the Login button but since the screen is large you can see the button halfway from the top.
Expected Behaviour
I want the Login button at the bottom to move into the app frame when user wants to input his login details.
App.js
import React from 'react';
import { StyleSheet, Text, View,TouchableOpacity, AppRegistry} from 'react-native';
import { StackNavigator } from 'react-navigation'; // 1.0.0-beta.23
import Login from './screens/Login';
class App extends React.Component {
render() {
return (
<View
style={styles.container} >
<View style={styles.boxContainer}>
<View style = {[styles.boxContainer, styles.boxOne]}>
<Text style={styles.paragraph}>Tido</Text>
</View>
<View style={styles.boxContainerToggle}>
<TouchableOpacity style={[styles.boxContainer, styles.boxTwo]} onPress={() => this.props.navigation.navigate('Login')}>
<Text style={styles.paragraph}>Login</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.boxContainer, styles.boxThree]}>
<Text style={styles.paragraph}>Sign Up</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
boxContainer: {
flex: 1, // 1:3
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
boxContainerToggle: {
flex: 1,
flexDirection: 'row'
},
boxOne: {
flex: 6, // 5:6
justifyContent: 'space-around',
alignItems: 'center',
},
boxTwo: {
flex: 1, // 1:6
backgroundColor: 'powderblue',
flexDirection: 'row',
width: '50%',
height: '100%'
},
boxThree: {
flex: 1, // 1:6
flexDirection: 'row',
backgroundColor: 'skyblue',
width: '50%',
height: '100%'
},
paragraph: {
margin: 24,
fontSize: 27,
fontWeight: 'bold',
textAlign: 'center',
color: '#34495e',
},
});
const appScreens = StackNavigator({
Index: { screen: App },
Login: { screen: Login }
})
AppRegistry.registerComponent('tido', () => appScreens);
export default appScreens;
Login.js
import React from 'react';
import {StyleSheet, View, TextInput, TouchableOpacity, Text, KeyboardAvoidingView} from 'react-native';
export default class Login extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.boxContainer}>
<View style = {[styles.boxContainer, styles.boxOne]}>
<TextInput
style={styles.inputBox}
placeholder="username,email or phone"
placeholderTextColor="#00000030"
underlineColorAndroid="transparent">
</TextInput>
<TextInput
style={styles.inputBox}
secureTextEntry={true}
placeholder="password"
placeholderTextColor="#00000030"
underlineColorAndroid="transparent">
</TextInput>
</View>
<View style={styles.boxContainerToggle}>
<TouchableOpacity
style={[styles.boxContainer, styles.boxTwo]}>
<Text style={styles.paragraph}>Login</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
boxContainer: {
flex: 1, // 1:3
justifyContent: 'center',
},
boxContainerToggle: {
flex: 1,
flexDirection: 'row',
},
boxOne: {
flex: 5, // 5:6
backgroundColor: 'white',
padding: 20
},
boxTwo: {
flex: 1, // 1:6
backgroundColor: '#252525',
flexDirection: 'row',
width: '100%',
height: '100%',
alignItems: 'center'
},
inputBox: {
height: 40,
backgroundColor: '#B6B6B630',
marginBottom: 10,
paddingHorizontal: 10,
},
paragraph: {
fontSize: 27,
fontWeight: 'bold',
textAlign: 'center',
color: '#FFFFFF',
},
});
The problem is that KeyboardAvoidingView cannot correctly apply padding if it's children doesn't have plain size set. In this particular case you need to figure out the screen dimenson and apply screen height (minus navigation bar height) to your root View style:
import { Dimensions } from 'react-native';
const { screenHeight: height } = Dimensions.get('window');
const styles = StyleSheet.create({
...
containerContent: {
height: screenHeight - navBarHeight,
justifyContent: 'center',
}
...
},
And apply it in your render method:
render() {
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.containerContent}>
...
</View>
</KeyboardAvoidingView>
);
}
I am still seeing that on keyboard open the toolbar is being pushed up out of visible area. This is the code :
<KeyboardAvoidingView style={styles.containerContent}>
<View style={styles.containerContent}>
<GiftedChat
messages={}
onSend={this.onSend}
renderAvatar={null}
user={{
_id: 1,
}}
imageStyle={{}}
/>
</View>
</KeyboardAvoidingView>
const styles = StyleSheet.create({
containerContent: {
height: Dimensions.get('window').height - kHeaderHeight,
justifyContent: 'center',
flex: 1,
},
});

Inner nested React Native swiper doesn't show any content

I'm trying to make two nested swipers on Android with React Native, using react-native-swiper. Each swiper works correctly when is separate, but when I add one to the other, the inner nested swiper doesn't show any content. It's a little bit weird, it recognized its children, I can swipe but Views are not rendered. Here is my simple demonstration example:
import React from 'react'
import {
Text,
View
} from 'react-native'
import Swiper from 'react-native-swiper'
const Dimensions = require('Dimensions');
const window = Dimensions.get('window');
var styles = {
wrapper: {
backgroundColor: 'transparent'
},
innerSwiper: {
width: window.width,
height: window.height / 3,
marginTop: 60,
backgroundColor: '#92BBD9'
},
slide1: {
flex: 1,
alignItems: 'center',
backgroundColor: '#9DD6EB'
},
slide2: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#97CAE5'
},
slide3: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#92BBD9'
},
text: {
color: '#fff',
fontSize: 30,
fontWeight: 'bold'
}
}
export default () =>
<Swiper style={styles.wrapper} showsButtons>
<View style={styles.slide1}>
<View style={styles.innerSwiper}>
<Swiper style={styles.wrapper} showsButtons>
<View style={styles.slide1}>
<Text style={styles.text}>Hello Swiper</Text>
</View>
<View style={styles.slide2}>
<Text style={styles.text}>Beautiful</Text>
</View>
<View style={styles.slide3}>
<Text style={styles.text}>And simple</Text>
</View>
</Swiper>
</View>
</View>
<View style={styles.slide2}>
<Text style={styles.text}>Beautiful</Text>
</View>
<View style={styles.slide3}>
<Text style={styles.text}>And simple</Text>
</View>
</Swiper>

React Native release a letter is missing

I watched a tutorial about React Native on YouTube.
I have built a simple stopper app. (Android) The problem is, in the release build, one of the letters is missing. I tried to build another simple app with just having "Hello" and in the release build in my phone instead of showing "Hello" I get "Hell".
Pictures:
Development build using Nexus 6 (AVD):
Release build with LG G4 (physical):
I don't know why this is happening. I appreciate any advice and help.
Edit: index.android.js:
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
View,
Text,
TouchableHighlight
} from 'react-native'
class flexbox extends Component {
render() {
return (
<View style={styles.container}>
<View style={[styles.header]}>
<View style={[styles.timeWrapper]}>
<Text style={styles.timer}>00:00.00</Text>
</View>
<View style={[styles.buttonWrapper]}>
<TouchableHighlight onPress={() => console.log('Start')} underlayColor="#2ecc71" style={[styles.button, styles.startButton]}>
<Text>Start</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => console.log('Lap')} underlayColor="#1abc9c" style={[styles.button, styles.lapButton]}>
<Text>Lap</Text>
</TouchableHighlight>
</View>
</View>
<View style={[styles.footer]}>
<Text>Laps</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
header: {
flex: 1
},
footer: {
flex: 1
},
timeWrapper: {
flex: 5,
justifyContent: 'center',
alignItems: 'center'
},
buttonWrapper: {
flex: 3,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center'
},
timer: {
fontSize: 60,
color: 'black'
},
button: {
borderWidth: 2,
height: 100,
width: 100,
borderRadius: 50,
justifyContent: 'center',
alignItems: 'center'
},
startButton: {
borderColor: '#2ecc71'
},
lapButton: {
borderColor: '#1abc9c'
}
})
AppRegistry.registerComponent('flexbox', () => flexbox)
You haven't supplied any code, but I'm guessing you have created a view with exact width and height, and in order to have the text in the middle, you added padding.
Here's an example of a working circle with text:
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.circle}>
<Text>Hello</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
circle: {
width: 50,
height: 50,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
borderColor: 'red',
borderWidth: 3,
}
});
Or see example in sketch

React Native scroll view not showing

I have a scroll view at the top level of the view hierarchy. I'm trying to get it to show its content but I haven't had any luck.
I see that the documentation says scroll views need a bounded height to work. I can't seem to get it to have a bounded height. This is what I have so far.
'use strict';
const React = require('react-native');
const {
StyleSheet,
Text,
View,
BackAndroid,
TextInput,
TouchableNativeFeedback,
ScrollView
} = React;
const ActionButton = require('./action-button'),
Dimensions = require('Dimensions');
module.exports = React.createClass({
handleBackButtonPress () {
if (this.props.navigator) {
this.props.navigator.pop();
return true;
}
return false;
},
componentWillMount () {
BackAndroid.addEventListener('hardwareBackPress', this.handleBackButtonPress);
},
componentWillUnmount () {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButtonPress);
},
onInputFocus (refName) {
setTimeout(() => {
let scrollResponder = this.refs.getScrollResponder();
scrollResponder.scrollNativeHandleToKeyboard(
React.findNodeHandle(this.refs[refName]),
110,
true
);
}, 50);
},
render: function() {
return (
<View style={styles.scrollWrapper}>
<ScrollView ref='scrollView' style={styles.scroller}>
<View style={styles.container}>
<View style={styles.header}>
<Text>New Post</Text>
<View style={styles.actions}>
<ActionButton handler={this.handleBackButtonPress} icon={'fontawesome|close'}
size={15} width={15} height={15} />
</View>
</View>
<View style={styles.content}>
<TextInput underlineColorAndroid={'white'}
placeholder={'Who\'s your professor?'}
ref='professor'
onFocus={this.onInputFocus.bind(this, 'professor')}
/>
<TextInput multiline={true}
underlineColorAndroid={'white'}
placeholder={'What do you think?'}
ref='post'
onFocus={this.onInputFocus.bind(this, 'post')}
/>
</View>
<View style={styles.footer}>
<TouchableNativeFeedback
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={{width: 50, height: 25, backgroundColor: 'green'}}>
<Text>Submit</Text>
</View>
</TouchableNativeFeedback>
</View>
</View>
</ScrollView>
</View>
);
}
});
const styles = StyleSheet.create({
scrollWrapper: {
flex: 1
},
scroller: {
flex: 1
},
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
backgroundColor: 'white',
padding: 5,
},
post: {
flex: 1,
},
actions: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignSelf: 'center'
},
header: {
flex: 1,
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: 35,
padding: 5,
flexDirection: 'row'
},
content: {
flex: 1,
position: 'absolute',
top: 35
},
footer: {
flex: 1,
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 35
}
});
EDIT: So I changed the background colors of all the components to something obvious. I was able to simplify the view, so now the ScrollView is the root of the component. The container view (the immediate child of the ScrollView) is the one who isn't filling all the available space. I'm still playing around with it but any help is much appreciated.
To fix this, you need to set flex: 1 to the parent's view. Then, for ScrollView, use contentContainerStyle={{flexGrow: 1}} rather than using style.
<View style={{flex: 1}}>
<ScrollView contentContainerStyle={{flexGrow: 1}}>
...
</ScrollView>
</View>
If you are using position: absolute, you need to specify a left:0, right:0 for it to work with your current setup, though I am not entirely sure position: absolute is needed at all. Try this:
content: {
flex: 1,
position: 'absolute',
top: 35,
left:0,
right:0,
bottom:0
},
Try setting removeClippedSubviews={false} as a property of and see what happens.

Categories

Resources