React Native- image wont fill screen? - css

This is frustrating. I have an image the exact same dimensions as the screen (of this device) and moreover same dimensions as the splash image. I just want it to fill the whole screen, above the other Views, for a few seconds after the splash goes away in order to do a custom animation.
Looking at other SO questions, Ive tried this so far (outside the main container of other app elements):
<Animated.View style = {styles.splash}>
<Image style = {{resizeMode: 'cover'}} source={require('./assets/splash2-txt.png')}/>
</Animated.View>
splash: {
flex: 1,
position: 'absolute',
zIndex: 4
},
and yet the image is scaled up and way off to the corner.
What is wrong here / how can I just fill the screen with the image?

Please use react-native ImageBackground for filling image in background, refer the example code given below
import React from "react";
import { ImageBackground, StyleSheet, Text, View } from "react-native";
const image = { uri: "https://reactjs.org/logo-og.png" };
const App = () => (
<View style={styles.container}>
<ImageBackground source={image} style={styles.image}>
<Text style={styles.text}>Inside</Text>
</ImageBackground>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column"
},
image: {
flex: 1,
resizeMode: "cover",
justifyContent: "center"
},
text: {
color: "grey",
fontSize: 30,
fontWeight: "bold"
}
});
export default App;

Use StyleSheet.absoluteFillObject in your image style instead of flex.
It should be something like...
import * as React from 'react';
import { Image, View, StyleSheet, StatusBar } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<Image style={styles.image} source={{uri: 'https://reactjs.org/logo-og.png'}} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
image: {
...StyleSheet.absoluteFillObject,
resizeMode: 'cover',
},
});

Related

Styling props not working, especially padding

I am still new to react-native and I have some troubles regarding the styling props of react-native.
I created a screen in my app and all my relevant code is this:
import React, {useState, useEffect} from 'react';
import {View, Text, StyleSheet, ActivityIndicator, Alert, ImageBackground} from 'react-native';
import { TextInput } from 'react-native-gesture-handler';
import {useDispatch, useSelector} from 'react-redux';
const NewLetterScreen = props =>{
return(
<View style={{flex:1}}>
<ImageBackground source={require('../components/pictures/welcome.png')} style={{width:"100%", height:"100%", alignItems: 'center', justifyContent: 'center'}}>
<ImageBackground source={require('../components/pictures/letters/paper1.jpg')} style={styles.paper}>
</ImageBackground>
</ImageBackground>
</View>
)
};
const styles = StyleSheet.create({
paper:{
width: "90%",
height: "90%"
}
});
export default NewLetterScreen;
The problem I face now is, that the "paper" I want to display is not centered, even tho I stricly declare this in the wrapping ImageBackground with justifyContent and alignItems. It is displaced to far up and to far on the left side and looks like this:
Also, if I try to use padding to get this stuff centered somehow, it doesnt work. I want to do padding from left and right, so horizontaly, but if I apply "paddingHorizontal: 50" to my styles.paper, the result is the following:
As you see, the "paddingHorizontal:50" works like a paddingLeft and that is definitely not what I intend.
I would be happy about any help regarding my styling props. Thanks in advance!
Why not add a margin of 10%? I always have problems with paddings. Try to avoid them.
Edit: Maybe it would help to just add a margin, instead of changing the width to 90%?
import React from "react";
import { ImageBackground, StyleSheet, Text, View } from "react-native";
const image = { uri: "https://reactjs.org/logo-og.png" };
const App = () => (
<View style={styles.container}>
<ImageBackground source={image} style={styles.image}>
<Text style={styles.text}>Inside</Text>
</ImageBackground>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "center"
},
image: {
flex: 1,
resizeMode: "cover",
justifyContent: "center",
margin: "10%"
},
text: {
color: "white",
fontSize: 42,
fontWeight: "bold",
textAlign: "center",
backgroundColor: "#000000a0"
}
});
export default App;
You can copy&paste this example on https://reactnative.dev/docs/imagebackground
You just need to add a wrapper for the inside image. You don't need margins or paddings.
const image1 = { uri: "https://images.unsplash.com/photo-1597768130867-4c06bf86a2f3?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80" };
const image2 = { uri: "https://images.unsplash.com/photo-1611085857146-7b13f8b0a74f?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=641&q=80" };
const App = () => (
<View style={{ flex: 1 }}>
<ImageBackground source={image1} style={styles.background}>
<View style={styles.wrapper}>
<ImageBackground source={image2}
resizeMode="cover"
style={styles.paper}>
</ImageBackground>
</View>
</ImageBackground>
</View>
);
const styles = StyleSheet.create({
background: {
width: "100%",
height: "100%",
alignItems: 'center',
justifyContent: 'center'
},
wrapper: {
width: "90%",
height: "90%",
alignItems: 'center',
justifyContent: 'center',
},
paper: {
width: "100%",
height: "100%"
}
});

React Native View shrinks to fit content when centered

I have a React Native View that I would like to have extend up to but not exceed a given width. Inside this View, I have a Text element that I would like to fill out the full width of its parent. It looks like this:
However, if I set the parent View to center align with alignSelf: 'center' the view will shrink to fit the text inside the Text view, like so:
Why does changing the alignment of a View cause it to change size, and how can I prevent this?
Expected Output:
Complete code to replicate this scenario:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.box}>
<Text style={styles.paragraph}>Text</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
box: {
backgroundColor: 'red',
height: 50,
maxWidth:200,
alignSelf: 'center' // <---REMOVE THIS LINE TO FILL VIEW
},
paragraph: {
textAlign: 'left',
backgroundColor: 'green',
},
});
Why adding width will not work
While setting a fixed width value would enforce the maximum size, it would prevent this element from shrinking down below that value. For this reason, specifying width is not a solution. Here is an example situation where the size of the view would extend past the display.
With width:
Expected:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.box}>
<Text style={styles.paragraph}>Text</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignContent:'center',//ADD THIS LINE
backgroundColor: '#ecf0f1',
padding: 8,
},
box: {
backgroundColor: 'red',
height: 50,
maxWidth:200,
},
paragraph: {
textAlign: 'left',
backgroundColor: 'green',
},
});
expo

React Navigation - padding bottom on header not working

In my React-Native app I have an icon and SearchBar in my header (from react navigation).
The following code:
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle:
<View style={{ flex: 1, flexDirection: "row", paddingHorizontal: 15, alignItems: "center" }}>
<StatusBar default style={{ flex: 1, height: getStatusBarHeight() }} />
<Icon name="chevron-left" size={28} />
<SearchBar round platform={"default"} placeholder="Search" containerStyle={{
flex: 1, backgroundColor: "transparent"
}} />
</View>,
headerStyle: {
backgroundColor: '#e54b4d',
}
};
}
outputs this:
So far so good. However, I want to have padding below the SearchBar. In other words, I want to have the distance from the top of the screen to the SearchBar as a padding below the SearchBar. (I can obtain the distance value using getStatusBarHeight() from rn-status-bar-height)
However, if I put paddingBottom: getStatusBarHeight() to the headerStyle, I get this result:
Basically, now I have the padding that I wanted, however, the StatusBar overlaps with the SearchBar.
How can I put paddingBottom without making the StatusBar and SearchBar overlap?
To change the padding of the header in your case you'll need to change headerTitleContainerStyle and not headerTitle.
For example :
headerTitleContainerStyle: { paddingVertical: 10 }
You can still check the doc.
For ios you will need to set backgroundColor.Below code is fit for android ios both.Hope it helps you.
import React, { Component } from 'react';
import { getStatusBarHeight } from 'react-native-status-bar-height';
import {
Modal,
Button,
View,
Text,
StyleSheet,
StatusBar,
Image,
Platform,
} from 'react-native';
import { SearchBar, Icon } from 'react-native-elements';
export default class AssetExample extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle: (
<View
style={{
flex: 1,
backgroundColor: Platform.OS === 'ios' ? '#e54b4d' : '',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 10,
height: StatusBar.currentHeight,
}}>
<Icon name="chevron-left" size={28} />
<SearchBar
round
platform={'default'}
placeholder="Search"
containerStyle={{
flex: 1,
backgroundColor: 'transparent',
}}
/>
</View>
),
headerStyle: {
backgroundColor: '#e54b4d',
},
};
};
render() {
return (
<View style={styles.container}>
<Text>Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});
when i checked your code on my device its properly viewing with padding.

Resizing an image to be centered

I have an image like so:
I am trying to make a 100x100 square and then centering that image inside it. I am able to get the 100x100 square with this code:
import * as React from 'react';
import { View, Image, StyleSheet } from 'react-native';
class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image
source={{ uri: 'https://storage.googleapis.com/iex/api/logos/GOOGL.png', }}
style={styles.image}
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
imageContainer: {
borderWidth: 1
},
image: {
width: 100,
height: 100
}
});
export default App;
However that cuts off the image:
Is there a way I can set a 100x100 width/height, but allow the image to resize as necessary to fit and be centered inside the square? Thanks!
Have you tried something like this? Its called resizeMode from React Native.
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
imageContainer: {
borderWidth: 1
},
image: {
width: 100,
height: 100,
resizeMode: 'contain'
}
});
Here is a link, for my has been very useful! is the jQuery Image Center. Centers an image by moving, cropping and filling spaces inside its parent container. Maintains aspect ratio.
http://boxlight.github.com/bl-jquery-image-center
For resize see the doc of resizeMode and resizeMethod in doc.

Make an item stick to the bottom using flex in react-native

Suppose this is the layout:
<View style={styles.container}>
<View style={styles.titleWrapper}>
...
...
</View>
<View style={styles.inputWrapper}>
...
...
</View>
<View style={styles.footer}>
<TouchableOpacity>
<View style={styles.nextBtn}>
<Text style={styles.nextBtnText}>Next</Text>
</View>
</TouchableOpacity>
</View>
</View>
I want to make the view with the styles of footer to position at the bottom of the screen. I tried giving the alignSelf property to the footer, but instead of positioning at the bottom, it positions it to the right side of the screen. How can I make the footer item stick to the end? Thank you.
I would use the following approach:
<View style={styles.container}>
<View style={styles.contentContainer}> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</View>
<View style={styles.footer}>
...
</View>
</View>
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
titleWrapper: {
},
inputWrapper: {
},
contentContainer: {
flex: 1 // pushes the footer to the end of the screen
},
footer: {
height: 100
}
});
This way the styles of titleWrapper and inputWrapper can be updated without breaking the layout of your app and the components themselves are easier to re-use :)
In React Native, the default value of flexDirection is column (unlike in CSS, where it is row).
Hence, in flexDirection: 'column' the cross-axis is horizontal and alignSelf works left/right.
To pin your footer to the bottom, apply justifyContent: 'space-between' to the container
for me the answer was to create a container view for the elements, then for the style.
bottomContainer: {
flex: 1,
justifyContent: 'flex-end',
}
Absolutely position is another way to fix footer, just like:
footer: {
position: 'absolute',
height: 40,
left: 0,
top: WINDOW_HEIGHT - 40,
width: WINDOW_WIDTH,
}
To fix a View to the bottom, simply use: marginTop: 'auto' .
This worked for me after searching like an hour on the net. I tried experimenting and it worked!
Consider a screen structure
<View style={styles.container}>
<View style={styles.body}> ... </View>
<View style={styles.footer}>...</View>
</View>
You can do it cleanly using Flexbox approach utilizing flex-grow.
const Styles = StyleSheet.create({
container:{
flexDirection: 'column', // inner items will be added vertically
flexGrow: 1, // all the available vertical space will be occupied by it
justifyContent: 'space-between' // will create the gutter between body and footer
},
})
Note: In case of nested elements, you have to ensure that the parent container has enough height to work with when using flexGrow. Set backgroundColor on parents and child to debug.
To do this you can use the Stylesheet element position: 'absolute'.
/*This is an Example to Align a View at the Bottom of Screen in React Native */
import React, { Component } from 'react';
import { StyleSheet, View, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<View style={styles.containerMain}>
<Text> Main Content Here</Text>
<View style={styles.bottomView}>
<Text style={styles.textStyle}>Bottom View</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
containerMain: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
bottomView: {
width: '100%',
height: 50,
backgroundColor: '#EE5407',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0, //Here is the trick
},
textStyle: {
color: '#fff',
fontSize: 18,
},
});
You can use this style:
row: {
flexDirection: 'row',
height: 50,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute', //Here is the trick
bottom: 0,
}
embed other content in a scrollview
<View style={styles.container}>
<ScrollView> {/* <- Add this */}
<View style={styles.titleWrapper}>
...
</View>
<View style={styles.inputWrapper}>
...
</View>
</ScrollView>
<View style={styles.footer}>
...
</View>
</View>
In react native, there are some properties like position: 'absolute', bottom: 0, which you will want to give to your button view
Quick example in essence, based on #David's answer:
<View style={{flex: 1}}>
<View style={{flex: 1}}>
<Text>Main content</Text>
</View>
<Text>Footer</Text>
</View>
import React from 'react'
import { View, StyleSheet } from 'react-native'
function moveToBottom(component) {
return (
<View style={styles.container}>
{component}
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-end',
marginBottom: 36
}
})
export default moveToBottom
Now in our screen, we just need to import:
import moveToBottom from 'library/utils/moveToBottom'
and wrap our button:
{
moveToBottom(
<ImageButton
style={styles.button}
title={strings.onboarding.welcome.button}
onPress={() => {
this.props.navigation.navigate('Term')
}} />
)
}
I tested it and I approve it's the best option to respect the layout without having fixed things to bottom, which is not possible if you use react-native-web in addition of react-native, because people resize and elements overlap on each over.
Source: https://medium.com/react-native-training/position-element-at-the-bottom-of-the-screen-using-flexbox-in-react-native-a00b3790ca42
I have a case in which I have to show a image in the bottom like this, as you can see the sky-blue image is not poped-up with keyboard.
so for this I have created a functional component for image in bottom.
import React, { useEffect, useState } from "react";
import { Keyboard, View, Image } from "react-native";
export const BottomImage = (props) => {
const [shouldShow, showImage] = useState(true);
useEffect(() => {
Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
return () => {
Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
};
}, []);
let _keyboardDidShow = () => {
showImage(false)
}
let _keyboardDidHide = () => {
showImage(true)
}
return (<ViewToRender show={shouldShow} src={props.image} />)
}
function ViewToRender(props) {
return props.show ? <Image style={{ position: 'absolute', bottom: 0 }} source={props.src} /> : <View />
}
and to use this Bottom image you have to pass your image to it like :
<BottomImage image={AppImage.signupbottom} />
This can be a bit tricky given that parent components can still affect the height of children with 'absolute' styles, I also tried doing "bottom: 0, height: 'auto'" like with normal HTML/CSS, but it didn't work out well, down the line I'll probably create a general component which makes sure the view can fit into the screen size. End result of view with contents
<View> component parameters
style={{
position: 'absolute',
left: 0,
padding: ContainerPadding,
top: TopOffset,
width: ScreenWidth
}}
onLayout={(event) => {
var {x, y, width, height} = event.nativeEvent.layout; // get the View's dimensions after 1st render
SetTopOffset(ScreenHeight - height - HeaderHeight); // Set 'top' to: screen size - height (of view) - parent top offset (optional if no parent offset)
}}
With useState:
const [TopOffset, SetTopOffset] = useState<number>(0); // Controls 'top' of screen
HeaderHeight is the height which is added to all my page components, you can remove this variable if you do not have any top spacing. (currently set to 64 default and this variable is updated based on device)
ScreenWidth & ScreenHeight are calculated here: export const ScreenWidth = Dimensions.get('screen').width; export const ScreenHeight = Dimensions.get('screen').height;
ContainerPadding is a general padding number used across my project (currently set to 12.5)

Resources