Reputation: 2943
I want to reproduce that style in my component (the border bottom). I am basically loading a rectangular image, then I want to rounded it at the bottom.
I think about :
Is there a way to do that in a proper style with React-Native ?
Thank you !
Upvotes: 1
Views: 8132
Reputation: 2451
@John Ruddell's answer is very helpful. I am able to design this by creating a mask and applied through SVG path. So, you need to install 2 libraries.
expo install react-native-svg
)npm install --save @react-native-community/masked-view
)Following code respect the aspect ratio of image. So, you need the set the aspect ratio of your image and adjust the value of curveAdjustment
in order to achieve your desired sharpness of curve.
import React from "react";
import {
Image,
View,
StyleSheet,
Text,
useWindowDimensions,
} from "react-native";
import MaskedView from "@react-native-community/masked-view";
import Svg, { Path } from "react-native-svg";
const logoUri = `http://66.media.tumblr.com/86b941b3445b80a518ea51208f48ab35/tumblr_ntpi99a6Pl1uounv1o1_500.png`;
function SplashScreen(props) {
const windowWidth = useWindowDimensions().width;
const imageAspectWidth = 375;
const imageAspectHeight = 332;
const curveAdjustment = 40;
const maskHeight = (imageAspectHeight / imageAspectWidth) * windowWidth;
const scaleFactor = imageAspectWidth / imageAspectHeight;
const scaledHeight = scaleFactor * maskHeight;
const controlPointX = windowWidth / 2.0;
const controlPointY = scaledHeight + curveAdjustment;
const curveCenterPointY = (controlPointY - maskHeight) / 2;
return (
<View style={styles.main}>
<MaskedView
style={[
styles.mask,
{
height: controlPointY - curveCenterPointY,
},
]}
maskElement={
<Svg height="100%" width="100%">
<Path
d={`M0 0 L${windowWidth} 0 L${windowWidth} ${maskHeight} Q${controlPointX} ${controlPointY} 0 ${maskHeight} Z`}
fill={"#fff"}
/>
</Svg>
}
>
<Image source={{ uri: logoUri }} style={styles.image} />
</MaskedView>
<Text>{"Tag line"}</Text>
</View>
);
}
const styles = StyleSheet.create({
image: {
flex: 1,
resizeMode: "stretch",
},
main: {
flex: 1,
},
mask: {
backgroundColor: "orange",
width: "100%",
},
});
export default SplashScreen;
Upvotes: 0
Reputation: 25862
This is possible, but it's a little tricky. The idea is you need to create a "mask" of sorts that you can apply the shape to. After doing that you can put the image as a child of the mask element so that it will essentially mask the area you want. It's probably possible to do it with a dynamic size, but I didn't take the time to come up with that solution, i'll leave that to you ;)
Hopefully this'll get you going in the right direction though.
First lets setup the app structure
class App extends Component {
render() {
return (
<View style={styles.app}>
<Mask />
</View>
);
}
}
Pretty straightforward, just a basic app with a mask component. I made it a component so you can pass props to it in the future (like the image uri for instance).
Then the mask component
const logoUri = `http://66.media.tumblr.com/86b941b3445b80a518ea51208f48ab35/tumblr_ntpi99a6Pl1uounv1o1_500.png`;
const Mask = (props) => (
<View style={styles.maskContainer}>
<View style={styles.mask}>
<Image
source={{ uri: logoUri }}
style={styles.img}
/>
</View>
</View>
)
The maskContainer
is a positioning element to help center the image.
The mask
uses the oval style approach but to get the edges to not round like border radius, we have to scale it 2x
The img
style needs to reverse the scaling so that the image itself is not warped :)
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500,
backgroundColor: "#e0e0e0",
width: 700,
height: 700
},
mask: {
width: 200,
height: 470,
borderBottomLeftRadius: 100,
borderBottomRightRadius: 100,
overflow: "hidden",
transform: [{ scaleX: 2 }]
},
img: {
height: 470,
width: 299,
left: 25,
position: "absolute",
transform: [{ scaleX: 0.5 }, { translate: "-50%" }]
},
maskContainer: {
position: "absolute",
left: "50%",
transform: [{ translate: "-50%" }]
}
});
Upvotes: 5
Reputation: 1410
Yep. clip-path property!
Just add: clip-path: circle(69.3% at 50% 30%)
To your class and it will work.
if you want to create it yourself, there's a generator here: https://bennettfeely.com/clippy/
Upvotes: -2