React-Native: Mask image with a bottom radius - react-native

How do I make the border bottom radius in an image?
And how can I mask the image to the green area?
I've tried the following codes, but I can't get the radius ratio in the image I've shared above
View Code:
<View style={styles.wrapper}>
<View style={styles.welcomeWrapper}>
<View style={styles.welcomeImageWrapper}>
<Image style={{width:'100%'}} source={require('../assets/images/test-slide.jpg')}/>
</View>
</View>
<View style={{
height: 100,
backgroundColor: colors.white,
justifyContent: 'flex-end',
alignItems: 'center'
}}>
<Text style={{marginBottom:50,fontSize:18,fontFamily:'Montserrat-Regular'}}>Deneme Text </Text>
</View>
</View>
Style Code:
wrapper:{
flex:1,
display: 'flex',
backgroundColor:colors.white,
},
welcomeWrapper:{
flex:1,
justifyContent:'center',
backgroundColor:colors.green01,
overflow: 'hidden',
position:'relative',
width:'100%',
borderBottomRightRadius:Dimensions.get('window').width/100*50,
borderBottomLeftRadius:Dimensions.get('window').width/100*50,
},

Seeing the shape of your image mask, I think you should use something like react-native-svg to create a real image mask.
Steps:
Set the background image in a View with a position: absolute, so that your image is always in the background and can be masked
Add react-native-svg to your project, for instance with yarn add react-native-svg, and link the library using react-native link. Finally, re-launch the metro bundler and compile your app (run-android or run-ios).
Design the svg mask (I used inkscape) and add it to the container's View, the mask should have the same backgroundColor as your text container.
A bit of styling using react's flexbox layout to be able to have almost the same look on every device. In this example, the mask takes 5/6 of the screen height as my mask flex number is 5 and my text flex is 1
So, this is what I ended up with:
import * as React from 'react';
import { Dimensions, Image, StyleSheet, Text, View } from 'react-native';
import { Path, Svg } from 'react-native-svg';
const mask = {
width: Dimensions.get('window').width,
height: 50,
bgColor: '#ecf0f1',
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'flex-end',
},
image: {
position: 'absolute',
},
mask: {
flex: 5,
justifyContent: 'flex-end',
},
textContainer: {
flex: 1,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: mask.bgColor,
},
text: {
fontSize: 50,
textAlign: 'center',
}
});
const App = () => (
<View style={styles.container}>
<Image style={styles.image} source={require('./assets/image.jpg')} />
<View style={styles.mask}>
<Svg width={mask.width} height={mask.height}>
<Path
fill={mask.bgColor}
d={`M 0 0 L 0 ${mask.height} L ${mask.width} ${mask.height} L ${mask.width} 0 A ${mask.width / 2} ${mask.height / 2} 0 0 1 ${mask.width / 2} ${mask.height / 2} A ${mask.width / 2} ${mask.height / 2} 0 0 1 0 0 z `} />
</Svg>
</View>
<View style={styles.textContainer}>
<Text style={styles.text}>Text</Text>
</View>
</View>
);
export default App;
And here is the result in an Android emulator
Hope this helps!
Link to snack: https://snack.expo.io/BJlZgpuB7 (but my image does not load on snack :( )

Related

Image fades into background React Native

I am making a react native app, and I'm having trouble getting an image to fade at the edges so that it blends into the background. I want it to look like the Netflix app, where the image doesn't end, but just fades into black Netflix image. I have tried wrapping my image component in a linear gradient, but that doesn't get rid of the hard edges of the image. I have to turn to opacity of the image all the way down to 0.1 to get that, which just destroys the quality of the image.
Here is the code for the component:
<LinearGradient
colors={["black", "white", "black"]}
locations={[0.2, 0.5, .8]}
>
<Image
key={image}
source={{ uri: image }}
style={styles.backgroundImage}
/>
</LinearGradient>
and the styles:
imageGradient: {
height: "70%",
marginTop: 150,
justifyContent: "center"
},
backgroundImage: {
height: "80%",
width: DEVICE_WIDTH,
opacity: 0.8
}
Rather than trying to make the Image partially transparent, you can make the LinearGradient on top of the Image transparent near the bottom.
For example:
import * as React from 'react';
import { Text, View, StyleSheet, Image } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import Constants from 'expo-constants';
export default function App() {
return (
<View style={styles.container}>
<View>
<Image style={{width: 300, height: 300}} source={require('./assets/snack-icon.png')} />
<LinearGradient
colors={['transparent','rgba(0,0,0,1.0)']}
style={{position: 'absolute', width: '100%', height: '100%'}}
/>
</View>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a shareable url.
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: 'black',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
color: 'white'
},
});
Snack link: https://snack.expo.dev/IWy50EQiX
Render Linear gradient absolutely above the image
also the colors should not be white, if you want the transparent color then use #00000000 to give transparent gradient
colors={['#000000', '#00000000', '#000000']}
Snack Link
code :
<View>
<Image
source={{
uri: 'https://miro.medium.com/max/1400/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg',
}}
style={styles.backgroundImage}
/>
<LinearGradient
style={{ ...StyleSheet.absoluteFillObject }}
colors={['#000000', '#00000000', '#000000']}
locations={[0.2, 0.5, 0.8]}
/>
</View>

How to achieve drop-shadow with no blur in React Native

I'm new using React Native and I'm trying to map the following component (made in web) but for React Native with no success:
Elevation and shadow properties does not do the trick because they add some blur to the resulting shadow. Which would be the proper way to handle this?
Regards
Use react-native-cardview
import React, { Component } from 'react';
import {
View,
ScrollView,
TextInput,
} from 'react-native';
import CardView from 'react-native-cardview';
import styles from './styles';
export default class Signup extends Component {
render() {
return (
<View style={{ flex: 1, backgroundColor: colors.whiteColor }}>
<ScrollView contentContainerStyle={styles.signupContainer}>
<View style={styles.signupInputs}>
<CardView
style={styles.cardStyle}
cardElevation={2}
cardMaxElevation={2}
cornerRadius={5}
>
<TextInput
underlineColorAndroid="transparent"
style={[styles.signupInput, styles.commonsignupStyle]}
placeholder="Nom *"
placeholderTextColor={colors.primaryColor}
/>
</CardView>
<CardView
style={styles.cardStyle}
cardElevation={2}
cardMaxElevation={2}
cornerRadius={5}
>
<TextInput
underlineColorAndroid="transparent"
style={[styles.signupInput, styles.commonsignupStyle]}
placeholder="Prénom *"
placeholderTextColor={colors.primaryColor}
/>
</CardView>
</View>
</ScrollView>
</View>
);
}
}
Edit:
For dynamic height, two lines or more of text, as asked for in the comments, I had to use another workaround.
https://snack.expo.io/7bVXvbmE0
const Label = () => {
return <View style={{width: 100, height: 50}}>
<View style={styles.topView}>
<Text>Hello world</Text>
<Text>Hi world</Text>
</View>
<View style={styles.shadowView} >
<Text style={{color: 'transparent'}}>Hello world</Text>
<Text style={{color: 'transparent'}}>Hi world</Text>
</View>
</View>;
}
Whatever dynamic text you have on the label, duplicate for the shadow label, but make it transparent. That way you are guaranteed that the shadow follows the top view.
Also, get rid of the hardcoded heights in the styles. For both top view and shadow view, their heights are informed by the text input, and the wrapper container's height is informed by the two views.
Lastly, change shadow view style's top to be just a few points above 0 to make sure you it peeks from under topview. You can adjust borderRadius of the shadow view to fit your preferences.
const styles = StyleSheet.create({
topView: {
width: '100%',
position: 'absolute',
top: 0, backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 25,
},
shadowView: {
position: 'absolute',
top: 3,
width: '100%',
zIndex: -10,
borderRadius: 17,
backgroundColor: '#ddd'}
});
Previous Post
A little bit hacky, but you can do this if you absolutely don't want any blur.
https://snack.expo.io/pWyPplcm3
const Label = () => {
return <View style={{width: 100, height: 30}}>
<View style={styles.topView}>
<Text>Hello world</Text>
</View>
<View style={styles.shadowView} />
</View>;
}
styles:
const styles = StyleSheet.create({
topView: {
height: 25,
width: '100%',
position: 'absolute',
top: 0, backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 15,
},
shadowView: {
position: 'absolute',
top: 0,
height: 28,
width: '100%',
zIndex: -10,
borderRadius: 13,
backgroundColor: '#ddd'}
});

How do I center one image over another in React Native

I'm trying to make a clock component with a face image and a needle centered on the clock in React Native.
does not allow embedding other Images.
I found a few posts for centering text over images but cannot find any way do center Image over images.
Edit:
I'm trying to find a way that avoids giving absolute position so the component can be dynamically sized.
If i understood correctly, you want to show one image over other image. With one as a Parent image and other as a child image without using absolute postion.
For this you can use ImageBackground Component provided by react-native and by setting its height and width with percentage value.
Below is the example :
Parent Image : Clock.png is an ImageBackground Component
Child Image : Needle.png is an Image Component
import React, { Component } from 'react'
import { StyleSheet, View, Text, ImageBackground, Image } from 'react-native'
export default class ImageView extends Component {
render() {
return (
<View
style={{
flex: 1
}}
>
<View
style={{
flex: 0.25,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'red'
}}
>
<Text style={{ color: 'white', fontSize: 26 }}>I am Header</Text>
</View>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
// backgroundColor: 'blue',
borderWidth: 1,
borderColor: 'red'
}}
>
<ImageBackground
source={require('#assets/Clock.png')}
style={{
height: '60%',
width: '100%'
}}
resizeMode="contain"
>
<Image
style={{
marginTop: '4.5%',
alignSelf: 'center',
height: '30%',
width: '100%'
}}
resizeMode="contain"
source={require('#assets/Needle.png')}
/>
</ImageBackground>
</View>
</View>
)
}
}
Same as you would handle this in regular old html,css.
Use position:absolute then align the items so that they match how you expect.

react-native style opacity for parent and child

react-native : I have one View and the child of View is an Image , I applied opacity: 0.5 for View and opacity: 0.9 for an Image but it doesn't apply for Image ,the parent opacity is applying for child , the child doesn't take independent opacity
Try changing the opacity using alpha-value of the background color instead. Then it should be possible applying different opacities for children.
For example:
<View style={{backgroundColor: 'rgba(0,0,0,0.5)'}}/>
React-Native 0.60+
There is a new opacity prop that you can pass in:
<View style={{opacity: 0.5}} />
React-Native 0.59.x and lower
Like this (with 50% at the end of color hash):
<View style={{backgroundColor: '#FFFFFF50'}} />
Or RGBa way:
<View style={{backgroundColor: 'rgba(0,0,0,0.5)'}} />
In react-native 0.6, you can use the opacity prop on a View. Example:
<View opacity={1.0} />
<View opacity={0.5} />
1.0 = opaque (alpha == 1.0)
0.0 = clear (alpha == 0.0)
See https://facebook.github.io/react-native/docs/0.6/view-style-props#opacity
Snack: https://snack.expo.io/S1KjXqe6N
If you want to display some text with transparent alpha opacity then I have the best way, just try.
TransparentBG:{
backgroundColor: '#00000070',
color:'#FFFFFF'
}
here, "70" indicates opacity %.
-Thanks
You need to use needsOffscreenAlphaCompositing like this-
<View needsOffscreenAlphaCompositing>
...
<View/>
If you want to change the opacity of a view that doesn't recognize the opacity prop (such as a TouchableOpacity), wrap it in a View first and change the opacity prop of that.
<View opacity={0.3}>
<TouchableOpacity>
</TouchableOpacity>
</View>
You can't change parent opacity without affecting child, so you should have absolute positioned background. For proper child positioning, you should add an additional container. Check out this snack: snack.expo.io/SkaHLjzr8
...
<View style={styles.container}>
<View style={styles.card} >
<View style={styles.background} />
<View style={styles.imageContainer}>
<Image style={styles.image} source="..." />
</View>
</View>
</View>
...
...
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
background: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'blue',
opacity: .5,
zIndex: 1,
},
card: {
height: 400,
},
imageContainer: {
...StyleSheet.absoluteFillObject,
justifyContent: 'center',
alignItems: 'center',
zIndex: 2,
opacity: 0.8,
},
image: {
width: 200,
height: 200
}
...
HACK FOR BACKGROUNDS OPACITY
Use combination of 2 backgroundColor in order to imitate the opacity
After playing sometimes and be lost on the internet to find a simple solucion, I realized that at the current React-Native Version V 0.64 the opacity for the backgrounds, at least as it is commonly used for Web Dev just is not suited for React-Native.
APP
Use ImageBackground Component --> DOCS:
Set you background image on the ImageBackground
import React from 'react';
import { ImageBackground, View, Text, StyleSheet, ScrollView} from 'react-native';
const App = () => {
return (
<ImageBackground style={ mainStyle.background } source={ { uri: "https://reactjs.org/logo-og.png" } } resizeMode="cover">
<ScrollView style={ mainStyle.overlay }> // Here its style will be used as opacity
<View style={ mainStyle.containerCenter}>
<View style={ mainStyle.homeTitleWraper}>
<Text style={ mainStyle.homeTitle }> Hello WOrld</Text>
</View>
</View>
</ScrollView>
</ImageBackground>
);};
export default App;
Style
Style, Here the First Child of the Background has to take the whole
screen size, with style overlay it will lay down like a thin blanket on top of the Background, imitating the opacity.
const mainStyle = StyleSheet.create({
background: {
width: "100%",
height: "100%",
},
overlay: {
backgroundColor: 'rgba(255, 255, 255, .5)' // HERE USE THE LAST DIGIT AS IF IT WERE OPACITY
},
containerCenter : {
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 30,
marginVertical: 60,
},
homeTitleWraper: {
paddingHorizontal: 40,
paddingVertical: 100,
},
homeTitle: {
fontSize: 40,
fontWeight: "900",
textAlign: "center",
textTransform: "uppercase",
color: "white",
fontStyle: "italic",
},
containerSmall: {
marginVertical: 10,
width: "100%"
}

How to stretch a static image as background in React Native?

I'd like to use a background image in my react native app,
the image is smaller than the screen, so I have to stretch it.
but it doesn't work if the image is loaded from asset bundle
var styles = StyleSheet.create({
bgImage: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'stretch',
resizeMode: 'stretch',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});
<Image source={require('image!background')} style={styles.bgImage}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
</Image>
it looks like this:
however, it works fine for a remote image, through source={{uri: 'background-image-uri'}}:
From Github issue: Image {require} is broken in React Native for Resizing, you could try <Image style={{width: null, height: null}}, hope that facebook would fix it soon.
The Image tag should generally not be treated as a container view.
Having an absolutely positioned wrapper containing your (stretched/contained) image appears to work well:
var styles = StyleSheet.create({
bgImageWrapper: {
position: 'absolute',
top: 0, bottom: 0, left: 0, right: 0
},
bgImage: {
flex: 1,
resizeMode: "stretch"
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
}
});
<View style={{ flex: 1 }}>
<View style={styles.bgImageWrapper}>
<Image source={require('image!background')} style={styles.bgImage} />
</View>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
</View>
You could always use the Dimensions module to get the width of the screen and set your image's width style to that value:
var Dimensions = require('Dimensions');
var {width, height} = Dimensions.get('window');
It also seems strange that a remote image works fine...you can try loading up a local static image with the uri syntax by using source={{uri: 'local_image_file_name' isStatic: true}}.
for me use undefined instead of null value. on typescript environment, it will be prompted not assignable
bgImage: {
flex: 1,
width: undefined,
height: undefined,
resizeMode: 'stretch',
},