React-Native中边框半径图像的自定义形状

时间:2019-05-23 07:21:48

标签: css react-native styled-components

我想在组件中(边框底部)重现该样式。 我基本上是在加载矩形图像,然后在底部将其四舍五入。

enter image description here

我在想:

  • border-bottom-right-radius和left,但对于屏幕的自定义形状来说并不准确。
  • 转换scaleX,但缩放图像比例(显然)
  • 创建具有自定义形状的白色图像并将其加载到屏幕底部,但是我想在图像底部添加阴影...对于白色图像,我无法做到这一点... < / li>

有没有办法用React-Native来以合适的方式做到这一点?

谢谢!

4 个答案:

答案 0 :(得分:1)

这是可能的,但是有点棘手。这个想法是,您需要创建可以应用形状的各种“蒙版”。之后,您可以将图像作为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,但要使边缘不像边界半径那样倒圆,我们必须将其缩放2倍
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!

答案 1 :(得分:0)

@John Ruddell的回答非常有帮助。 我可以通过创建遮罩并通过SVG路径进行设计。因此,您需要安装2个库。

  1. react-native-svgexpo install react-native-svg
  2. react-native-masked-viewnpm 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;

最终结果

Screenshot

答案 2 :(得分:-1)

我假设您要保持左右笔直的边缘,而仅使底边缘弯曲。 Here's one way,带有CSS和两个堆叠的divs

您必须调整CSS和图像大小,才能使半径完全符合您的喜好。对于大于divs并用background-position:background-repeat: no-repeat调整过的图像,效果最佳。您也可以对顶部div使用border-leftborder-right,以使其没有顶部或底部框架。

.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>

答案 3 :(得分:-2)

是的。剪辑路径属性!

只需添加: 剪切路径:圆(69.3%,50%为30%)

对您的班级来说,它将起作用。

如果您想自己创建它,这里有一个生成器: https://bennettfeely.com/clippy/