React-Native 中边框半径图像的自定义形状
Custom shape for border radius image in React-Native
我想在我的组件(边框底部)中重现该样式。
我基本上是加载一个矩形图像,然后我想在底部把它弄圆。
我考虑:
- border-bottom-right-radius 和 left,但与屏幕的自定义形状不准确。
- 变换 scaleX,但它缩放图像比例(显然)
- 创建一个带有自定义形状的白色图像并将其加载到屏幕底部,但我想在图像底部添加阴影...使用白色图像我无法做到这一点... .
有没有办法使用 React-Native 以适当的方式做到这一点?
谢谢!
是的。 clip-path 属性!
只需添加:
clip-path:圆形(69.3% 在 50% 30%)
到你的class,它会起作用。
如果你想自己创建,这里有一个生成器:
https://bennettfeely.com/clippy/
我假设您想要保持笔直的左边缘和右边缘,只有底部边缘是弯曲的。 Here's one way 与 CSS 和两个堆叠 divs
。
您必须根据自己的喜好调整半径的 CSS 和图像大小。它最适用于大于 divs
的图像,使用 background-position:
和 background-repeat: no-repeat
进行调整。您还可以使用 border-left
和 border-right
使顶部 div 没有顶部或底部框架。
.imagediv {
width: 400px;
height: 300px;
border-radius: 0 0 50% 50%;
background-image: url("https://www.scriptbarrel.com/images/swim.png");
background-position: 50% 20%;
background-repeat: no-repeat;
position: relative;
box-shadow: 0px 5px 4px #999;
z-index: 0;
margin: 0 auto;
}
.topdiv {
margin: 0 auto;
left: -10px;
width: 340px;
height: 300px;
border-top: 15px solid white;
border-left: 40px solid white;
border-right: 40px solid white;
position: absolute;
z-index: 1;
}
<html><head>
<title>CSS fun</title>
</head>
<body>
<div class = "imagediv">
<div class = "topdiv"></div>
</div>
</body>
</html>
这是可能的,但有点棘手。这个想法是你需要创建一个可以应用形状的 "mask" 种类。这样做之后,您可以将图像作为遮罩元素的子元素,以便它基本上遮住您想要的区域。可能可以使用动态大小来完成,但我没有花时间想出那个解决方案,我会把它留给你;)
但愿这会让您朝着正确的方向前进。
首先让我们设置应用程序结构
class App extends Component {
render() {
return (
<View style={styles.app}>
<Mask />
</View>
);
}
}
非常简单,只是一个带有遮罩组件的基本应用程序。我把它变成了一个组件,这样你以后就可以将道具传递给它(例如图像 uri)。
然后是遮罩组件
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>
)
maskContainer
是一个帮助图像居中的定位元素。
mask
使用 oval style approach 但要使边缘不像边界半径那样圆润,我们必须将其缩放 2x
img
样式需要反转缩放,这样图像本身就不会变形 :)
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%" }]
}
});
See it working on this fiddle!
@John Ruddell 的回答很有帮助。
我可以通过创建蒙版并通过 SVG 路径应用来设计它。所以,你需要安装2个库。
- react-native-svg (
expo install react-native-svg
)
- react-native-masked-view (
npm install --save @react-native-community/masked-view
)
以下代码尊重图像的纵横比。因此,您需要设置图像的纵横比并调整 curveAdjustment
的值,以达到您想要的曲线锐度。
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;
最终结果
我想在我的组件(边框底部)中重现该样式。 我基本上是加载一个矩形图像,然后我想在底部把它弄圆。
我考虑:
- border-bottom-right-radius 和 left,但与屏幕的自定义形状不准确。
- 变换 scaleX,但它缩放图像比例(显然)
- 创建一个带有自定义形状的白色图像并将其加载到屏幕底部,但我想在图像底部添加阴影...使用白色图像我无法做到这一点... .
有没有办法使用 React-Native 以适当的方式做到这一点?
谢谢!
是的。 clip-path 属性!
只需添加: clip-path:圆形(69.3% 在 50% 30%)
到你的class,它会起作用。
如果你想自己创建,这里有一个生成器: https://bennettfeely.com/clippy/
我假设您想要保持笔直的左边缘和右边缘,只有底部边缘是弯曲的。 Here's one way 与 CSS 和两个堆叠 divs
。
您必须根据自己的喜好调整半径的 CSS 和图像大小。它最适用于大于 divs
的图像,使用 background-position:
和 background-repeat: no-repeat
进行调整。您还可以使用 border-left
和 border-right
使顶部 div 没有顶部或底部框架。
.imagediv {
width: 400px;
height: 300px;
border-radius: 0 0 50% 50%;
background-image: url("https://www.scriptbarrel.com/images/swim.png");
background-position: 50% 20%;
background-repeat: no-repeat;
position: relative;
box-shadow: 0px 5px 4px #999;
z-index: 0;
margin: 0 auto;
}
.topdiv {
margin: 0 auto;
left: -10px;
width: 340px;
height: 300px;
border-top: 15px solid white;
border-left: 40px solid white;
border-right: 40px solid white;
position: absolute;
z-index: 1;
}
<html><head>
<title>CSS fun</title>
</head>
<body>
<div class = "imagediv">
<div class = "topdiv"></div>
</div>
</body>
</html>
这是可能的,但有点棘手。这个想法是你需要创建一个可以应用形状的 "mask" 种类。这样做之后,您可以将图像作为遮罩元素的子元素,以便它基本上遮住您想要的区域。可能可以使用动态大小来完成,但我没有花时间想出那个解决方案,我会把它留给你;)
但愿这会让您朝着正确的方向前进。
首先让我们设置应用程序结构
class App extends Component {
render() {
return (
<View style={styles.app}>
<Mask />
</View>
);
}
}
非常简单,只是一个带有遮罩组件的基本应用程序。我把它变成了一个组件,这样你以后就可以将道具传递给它(例如图像 uri)。
然后是遮罩组件
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>
)
maskContainer
是一个帮助图像居中的定位元素。
mask
使用 oval style approach 但要使边缘不像边界半径那样圆润,我们必须将其缩放 2x
img
样式需要反转缩放,这样图像本身就不会变形 :)
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%" }]
}
});
See it working on this fiddle!
@John Ruddell 的回答很有帮助。 我可以通过创建蒙版并通过 SVG 路径应用来设计它。所以,你需要安装2个库。
- react-native-svg (
expo install react-native-svg
) - react-native-masked-view (
npm install --save @react-native-community/masked-view
)
以下代码尊重图像的纵横比。因此,您需要设置图像的纵横比并调整 curveAdjustment
的值,以达到您想要的曲线锐度。
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;