I have a ScrollView which has two children, and I want each of the children to be the full height of the available space on the screen, meaning view 1 fills the whole screen, and then I scroll down to start to see part of slide 2. If I scroll all the way down, I should only see slide 2.
I can't figure out how to get this to happen. What is currently happening is that each child is filling half of the available vertical space, so I don't get any scrolling.
Any ideas how I can achieve this layout? Thanks!
Current UI: https://i.imgur.com/fZdbUSo.png
Desired UI:
Before scrolling: https://i.imgur.com/EsQpVMm.png
After scrolling all the way down: https://i.imgur.com/PfXQyfI.png
Code:
import React from "react";
import {
StyleSheet,
ScrollView,
Text,
View
} from "react-native";
const Home = () => {return (
<ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollViewContainer}>
<View style={styles.slide1}>
<Text>this should be full height</Text>
</View>
<View style={styles.slide2}>
<Text>this should also be full height, but only be visible once i scroll down</Text>
</View>
</ScrollView>
)};
const styles = StyleSheet.create({
slide1: {
justifyContent: "center",
flexGrow: 1,
backgroundColor: "blue"
},
slide2: {
justifyContent: "center",
flexGrow: 1,
backgroundColor: "green"
},
scrollView: {
flex: 1
},
scrollViewContainer: {
flexGrow: 1
}
});
export default Home;
I'm not sure if there is a way to do what you are trying to accomplish with flex layout.
I would suggest getting the height of the visible container - either the height of the window or calculate it some other way, possibly using onLayout of the containing view and getting the height there, and then you have to set the height of your two inner views using that. You may need to wrap your scrollView in a View and use its onLayout function instead of the one for the scrollView.
To do the second part of your question, scrollView has a snapToInterval prop you can set.
Let me know how that goes for you or if you need code examples.
I was able to get this to work by using onLayout() as Doug Watkins suggested and updating the height of the children to match the height of the parent ScrollView:
import React, { Component } from "react";
import {
StyleSheet,
ScrollView,
Text,
View,
LayoutChangeEvent
} from "react-native";
class Home extends Component {
state = {
slideHeight: 0
};
updateHeight = (e: LayoutChangeEvent) => {
this.setState({ slideHeight: e.nativeEvent.layout.height });
};
styles = StyleSheet.create({
slide1: {
justifyContent: "center",
backgroundColor: "blue"
},
slide2: {
justifyContent: "center",
backgroundColor: "green"
},
scrollView: {
flex: 1
},
scrollViewContainer: {
flexGrow: 1
}
});
render () {
return (
<ScrollView style={this.styles.scrollView} contentContainerStyle={this.styles.scrollViewContainer} onLayout={this.updateHeight}>
<View style={[this.styles.slide1, {height: this.state.slideHeight}]}>
<Text>this should be full height</Text>
</View>
<View style={[this.styles.slide2, {height: this.state.slideHeight}]}>
<Text>this should also be full height, but only be visible once i scroll down</Text>
</View>
</ScrollView>
)
}
};
export default Home;
You can use react-native-swiper to achieve this functionality. Set your data or component in swiper slides and set props horizontal={false} to get vertical sliding.
So, first install react-native-swiper using this command:
npm i react-native-swiper --save
Now, import and use it as following :
import React from "react";
import { StyleSheet, ScrollView, Text, View } from "react-native";
import Swiper from "react-native-swiper";
const { width } = Dimensions.get("window");
const { height } = Dimensions.get("window");
const Home = () => {
return (
<Swiper style={{}} height={height} horizontal={false}>
<View style={styles.slide1}>
<Text>this should be full height</Text>
</View>
<View style={styles.slide2}>
<Text>
this should also be full height, but only be visible once i scroll
down
</Text>
</View>
</Swiper>
);
};
const styles = StyleSheet.create({
slide1: {
justifyContent: "center",
flexGrow: 1,
backgroundColor: "blue",
},
slide2: {
justifyContent: "center",
flexGrow: 1,
backgroundColor: "green",
},
scrollView: {
flex: 1,
},
scrollViewContainer: {
flexGrow: 1,
},
});
export default Home;
I know this may not perfect solution, but it work around. Swiper originally made up with scrollview, so there may be not problem.
Related
How can I stretch my subview across 100% width of its parent, minus 20px margin on each side? In other words, I need it to fill the width of the parent, with 20px open on each side.
I know in React-Native I can use width: '80%' to make my subview's width relative to that of its parent, but then it's not always precisely 20px on the sides. I also know that I can use alignSelf: 'stretch', however that is not working for me - it has unexpected / unreliable results. I don't want to use Dimensions, as the parent will not always be the device's screen, so Dimensions.get('window').width is inadequate for this problem.
What other options do I have?
Use nested View. You can try here: https://snack.expo.io/#vasylnahuliak/stackoverflow-67989491
import React, { useState } from 'react';
import { Text, View, StyleSheet } from 'react-native';
const App = () => {
return (
<View style={styles.container}>
<View style={styles.child}>
<Text style={styles.childText}>child</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 24,
backgroundColor: 'tomato',
},
child: {
height: 150,
backgroundColor: 'navy',
},
childText: {
color: 'white',
},
});
export default App;
I have this code and it works fine to shows the overlay the requested page for 5sec and Hide to shows the requested page's contents, But when the Loader indicator disappeared its (red) background still there, how to hide the background too?
It has two part firsts one for creating Loading Indicator to be hidden after 5 sec.
Working example on Expo.io:
Live Demo -
This is requested page's code: (Please, notice has to be called from /screens)
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Loader from './screens/Loader';
export default function App() {
return (
<View style={styles.container}>
<Loader /> //<--- I put the Loader here
<Text style={styles.paragraph}>
This is the requested page should be be covered by indicator background (Red color) <br/ >
The Loader disappear after 5 sec.<br />
But, its background still there!!
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
And the Loader.js code is :
import React, { Component } from 'react';
import { ActivityIndicator, View, Text, TouchableOpacity, StyleSheet } from 'react-native';
class Loader extends Component {
state = { animating: true }
closeActivityIndicator = () => setTimeout(() => this.setState({
animating: false }), 5000)
componentDidMount = () => this.closeActivityIndicator()
render() {
const animating = this.state.animating
return (
<View style = {styles.container}>
<ActivityIndicator
animating = {animating}
color = '#bc2b78'
size = "large"
style = {styles.activityIndicator}/>
</View>
)
}
}
export default Loader
const styles = StyleSheet.create ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 0,
position: 'absolute',
height: "100%",
width: "100%",
backgroundColor: 'red',
opacity: 0.7
},
activityIndicator: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
The problem is you are always rendering the Loader and its always visible, so the easiest way to handle this would be to return null and hide the loader when its not necessary like below.
render() {
const animating = this.state.animating;
if(!this.state.animating)
return null;
return (
<View style = {styles.container}>
<ActivityIndicator
animating = {animating}
color = '#bc2b78'
size = "large"
style = {styles.activityIndicator}/>
</View>
)
}
i'm building a simple bughouse (4-person chess) game as my first React Native app, and i'm a little confused about a styling issue. the issue occurs when rendering an ImageBackground, which contains a View, which contains a grid of Views (the chess board). when using the code laid out following this question, the View is not contained within the screen (see screenshot below). how do i set the style of a View contained within an ImageBackground so that the View stays contained within the ImageBackground?
screenshot
i've tried about everything i can think of but nothing has helped. i suspect the issue has something to do with the dimensions of the ImageBackground not being set properly and actually extending past the edge of the screen. when i comment out the line that says width: Dimensions.get('screen').width, in styles.board in BoardView.js, the image for the ImageBackground also fills up the same too-big space.
here is views/Game.js:
import 'react-native-gesture-handler';
import React, { Component } from 'react';
import {
SafeAreaView,
View,
StyleSheet,
Platform,
StatusBar,
} from 'react-native';
import { BoardView } from '../components/BoardView';
import { Navbar } from '../components/Navbar';
export function Game () {
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
},
bottomBar: {
flex: 2,
width: '100%',
backgroundColor: 'black',
justifyContent: 'center',
},
});
return (
<SafeAreaView style={styles.mainContainer}>
<Navbar />
<BoardView />
<View style={styles.bottomBar}>
</View>
</SafeAreaView>
);
}
here is components/BoardView.js:
import React, { Component } from 'react';
import {
StyleSheet,
ImageBackground,
Dimensions
} from 'react-native';
import { Pieces } from "./Pieces";
export function BoardView () {
const styles = StyleSheet.create({
board: {
flex: 10,
width: Dimensions.get('screen').width,
},
});
return (
<ImageBackground
resizeMode='contain'
style={styles.board}
source={require('../assets/board.png')}
>
<Pieces />
</ImageBackground>
);
}
here is components/Pieces.js:
import 'react-native-gesture-handler';
import React, { Component } from 'react';
import {
View,
StyleSheet,
Text,
} from 'react-native';
export function Pieces () {
const styles = StyleSheet.create({
grid: {
borderColor: 'green',
borderWidth: 5,
alignSelf: 'center',
aspectRatio: 1,
overflow: 'visible',
width: '100%',
height: '100%',
},
gridRow: {
flexDirection: 'row',
flex: 1,
},
gridTile: {
borderWidth: 1,
borderColor: 'green',
flex: 1,
height: '100%',
},
test: {
color: 'green',
},
});
let pieces = [
[['bRook'],['bKnight'],['bBishop'],['bQueen'],['bKing'],['bBishop'],['bKnight'],['bRook']],
[['bPawn'],['bPawn'],['bPawn'],['bPawn'],['bPawn'],['bPawn'],['bPawn'],['bPawn']],
[[''],[''],[''],[''],[''],[''],[''],['']],
[[''],[''],[''],[''],[''],[''],[''],['']],
[[''],[''],[''],[''],[''],[''],[''],['']],
[[''],[''],[''],[''],[''],[''],[''],['']],
[['wPawn'],['wPawn'],['wPawn'],['wPawn'],['wPawn'],['wPawn'],['wPawn'],['wPawn']],
[['wRook'],['wKnight'],['wBishop'],['wQueen'],['wKing'],['wBishop'],['wKnight'],['wRook']],
];
return (
<View style={styles.grid}>
{pieces.map((row, index) =>(
<View style={styles.gridRow} key={index}>
{row.map((tile, index) => (
<View style={styles.gridTile} key={index}>
<Text style={styles.test}>
{tile}
</Text>
</View>
))}
</View>
))}
</View>
);
}
how do i set the style so that the View stays contained within the ImageBackground? thank you very much for your help!
I'm new here on react native, And i was trying to align the back button to the left, But keeping the title on the center, But nothing works, This is the code.
The TouchableOpacity is the back button, And the Text is the title, Each one have his own style.
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, Image } from 'react-native';
import { Colors } from '../Variables';
class Header extends Component {
render(){
return(
<View style={ styles.headerStyle }>
<TouchableOpacity>
<Image style={ styles.backBtnStyle } source={ require('../graphics/icons/arrow_left_white.png') }/>
</TouchableOpacity>
<Text style={ styles.titleStyle }>
TITLE
</Text>
</View>
);
}
}
const styles = {
headerStyle: {
backgroundColor: Colors.primary,
flexDirection: 'row',
alignItems: 'center',
},
backBtnStyle: {
width: 25,
height: 25,
margin: 10,
},
titleStyle: {
color: '#fff',
textAlign: 'center',
fontSize: 25,
}
};
export default Header;
Thanks for helping.
You should try to view this document about Flex in React native and practive more to mastered it.
In Your case, just simplify add alignSelf: 'flex-start' to backBtnStyle StyleSheet to make it in first of your parent component
Here is demo code:
headerStyle: {
backgroundColor: Colors.primary,
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-start'
},
<TouchableOpacity style={styles.backBtnStyle}>
<Image source={require('../graphics/icons/arrow_left_white.png') }/>
</TouchableOpacity>
You see: TouchableOpacity contain a Viewable Layout and wrap your image then you need to set style for TouchableOpacity to make flex work, not at Image.
From React NativeTouchableOpacity Documents: Opacity is controlled by wrapping the children in an Animated.View, which is added to the view hierarchy. Be aware that this can affect layout.
You can see Touchable Opacity Document here
Note: Set Your StyleSheet on StyleSheet.create() to make it create one and only one time when your bundle load. It make your app light weight and faster
Read about React Native StyleSheet here
You are using alignItems: 'center' in your container, so everything will be in the center.
In your case, there are a lot of solutions available. The more simple is just use a position: absolute; left: 15 in the styles.backBtnStyle.
I'm building a React Native app for the first time using an iOS Simulator with XCode, and it seems that my elements on the bottom of the screen are being cut off, as if the screen can only scroll so far. I've tried changing the overall container View's height, but it doesn't change how far down I can scroll. I've also tried removing the styling, as well as changing View to ScrollView, but neither helped. Another strange thing is that I need to add paddingTop, otherwise, the first Text is displayed over the time in the simulator
Here's the code:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Fields from './components/Fields.js'
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Calculator</Text>
<Text>1099 Calculator</Text>
<Fields />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
paddingTop: 50
},
});
Here's the top of the screen without the padding
And here's how it looks cut off
This is an issue I also had. To fix it just wrap your container with another view without padding but with flex. So like this:
export default class App extends React.Component {
render() {
return (
<View style={styles.main}>
<View style={styles.container}>
<Text>Calculator</Text>
<Text>1099 Calculator</Text>
<Fields />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
paddingTop: 50
},
main: {
flex: 1
}
});
I was facing the same problem, it turned out to be the padding that I added to my ScrollView. Maybe it is not the solution, it is simply to discard ideas..