如何在 React Native 中创建聊天气泡的卷曲箭头/尾部

问题描述 投票:0回答:3

我目前正在用react-native制作聊天气泡。由于我是反应原生的新手,我首先尝试在浏览器上制作聊天气泡,然后尝试在反应原生中复制相同的内容。我正在努力复制反应本机中的箭头。有什么想法/建议吗?

普通 HTML/CSS:

<div>
  <p class="to-me">Hey!</p>
</div>

div {
  padding:20px;
  justify-self: center;
  align-self: center;
  text-align: left;
  display: flex;
  flex-direction: column;
  width: 450px;
}
div p {
  font-size: 16px;
  line-height: 1.4;
  margin: 1px 0;
  padding: 8px 17px 6px 13px;
  max-width: 380px;
  position: relative;
  border-radius: 18px;
}
div p:after {
  position: absolute;
  content: "";
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: -1;
}
div p.to-me {
  color: black;
  align-self: flex-start;
  background-color: #E5E5EA;
}
div p.to-me:after {
  background: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' width='15.515px' height='17.5px' viewBox='32.484 17.5 15.515 17.5' enable-background='new 32.484 17.5 15.515 17.5'><path fill='#E5E5EA' d='M38.484,17.5c0,8.75,1,13.5-6,17.5C51.484,35,52.484,17.5,38.484,17.5z'/></svg>") left bottom no-repeat;
  left: -6px;
}

结果:

Chat Bubble

React-Native 版本:

<View style={[styles.balloon, {backgroundColor: '#1084ff'}]}>
      <Text style={{paddingTop: 5, color: 'white'}}>Hey!</Text>
      <View
      style={[
        styles.arrowContainer,
        styles.arrowLeftContainer,
      ]}
    >
      <View style={styles.arrowLeft} />
    </View>
    </View>
  </View>


item: {
   marginVertical: 14,
   flexDirection: 'row'
},
itemIn: {
    marginLeft: 10
},
itemOut: {
   alignSelf: 'flex-end',
   marginRight: 10
},
balloon: {
   maxWidth: scale(250),
   paddingHorizontal: 15,
   paddingTop: 10,
   paddingBottom: 15,
   borderRadius: 20,
},
arrowContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    zIndex: -1
    // backgroundColor: 'red'
},
arrowLeftContainer: {
    justifyContent: 'center',
    alignItems: 'flex-start',
    // backgroundColor: 'green'
},

arrowLeft: {
    left: -20,
}

结果: enter image description here

我几乎复制了泡沫。只是在箭头部分挣扎。有什么想法/建议吗?

html css react-native flexbox
3个回答
27
投票

让箭头出现比我想象的要难,特别是当你考虑不同的屏幕尺寸、不同的平台(iOS 和 android)时。是的,@Panagiotis Vrs 提到它在两个平台上看起来不会 100% 相同,这是正确的。尽管如此,我尝试使用 react-native-svgreact-native-size-matters 来实现相同的目标。

我正在分享我的代码,也许有人可以即兴创作并使其变得更好。

HTML 部分

<View style={[styles.item, styles.itemIn]}>
        <View style={[styles.balloon, {backgroundColor: 'grey'}]}>
          <Text style={{paddingTop: 5, color: 'white'}}>Hey! How are you?</Text>
          <View
          style={[
            styles.arrowContainer,
            styles.arrowLeftContainer,
          ]}
        >
        
           <Svg style={styles.arrowLeft} width={moderateScale(15.5, 0.6)} height={moderateScale(17.5, 0.6)} viewBox="32.484 17.5 15.515 17.5"  enable-background="new 32.485 17.5 15.515 17.5">
                <Path
                    d="M38.484,17.5c0,8.75,1,13.5-6,17.5C51.484,35,52.484,17.5,38.484,17.5z"
                    fill="grey"
                    x="0"
                    y="0"
                />
            </Svg>
        </View>
        </View>
      </View>


      <View style={[styles.item, styles.itemOut]}>
        <View style={[styles.balloon, {backgroundColor: '#1084ff'}]}>
          <Text style={{paddingTop: 5, color: 'white'}}>Hey! I am good. How are you?</Text>
          <View
          style={[
            styles.arrowContainer,
            styles.arrowRightContainer,
          ]}
        >
           <Svg style={styles.arrowRight} width={moderateScale(15.5, 0.6)} height={moderateScale(17.5, 0.6)} viewBox="32.485 17.5 15.515 17.5"  enable-background="new 32.485 17.5 15.515 17.5">
                <Path
                    d="M48,35c-7-4-6-8.75-6-17.5C28,17.5,29,35,48,35z"
                    fill="#1084ff"
                    x="0"
                    y="0"
                />
            </Svg>
        </View>
        </View>
      </View>





       <View style={[styles.item, styles.itemOut]}>
        <View style={[styles.balloon, {backgroundColor: '#1084ff'}]}>
          <Text style={{paddingTop: 5, color: 'white'}}>Check this Image out !!!</Text>
          <View
          style={[
            styles.arrowContainer,
            styles.arrowRightContainer,
          ]}
        >
           <Svg style={styles.arrowRight} width={moderateScale(15.5, 0.6)} height={moderateScale(17.5, 0.6)} viewBox="32.485 17.5 15.515 17.5"  enable-background="new 32.485 17.5 15.515 17.5">
                <Path
                    d="M48,35c-7-4-6-8.75-6-17.5C28,17.5,29,35,48,35z"
                    fill="#1084ff"
                    x="0"
                    y="0"
                />
            </Svg>
        </View>
        </View>
      </View>


       <View style={[styles.item, styles.itemOut]}>
        <View style={[styles.balloon, {backgroundColor: '#1084ff'}]}>
        
        <Image
            styleName="small"
            borderRadius={5}
            source={{ uri: 'https://shoutem.github.io/img/ui-toolkit/examples/image-3.png'}}
            />
          <View
          style={[
            styles.arrowContainer,
            styles.arrowRightContainer,
          ]}
        >
           <Svg style={styles.arrowRight} width={moderateScale(15.5, 0.6)} height={moderateScale(17.5, 0.6)} viewBox="32.485 17.5 15.515 17.5"  enable-background="new 32.485 17.5 15.515 17.5">
                <Path
                    d="M48,35c-7-4-6-8.75-6-17.5C28,17.5,29,35,48,35z"
                    fill="#1084ff"
                    x="0"
                    y="0"
                />
            </Svg>
        </View>
        </View>
      </View>


     <View style={[styles.item, styles.itemIn]}>
        <View style={[styles.balloon, {backgroundColor: 'grey'}]}>
          <Text style={{paddingTop: 5, color: 'white'}}>Nice Picture</Text>
          <View
          style={[
            styles.arrowContainer,
            styles.arrowLeftContainer,
          ]}
        >
        
           <Svg style={styles.arrowLeft} width={moderateScale(15.5, 0.6)} height={moderateScale(17.5, 0.6)} viewBox="32.484 17.5 15.515 17.5"  enable-background="new 32.485 17.5 15.515 17.5">
                <Path
                    d="M38.484,17.5c0,8.75,1,13.5-6,17.5C51.484,35,52.484,17.5,38.484,17.5z"
                    fill="grey"
                    x="0"
                    y="0"
                />
            </Svg>
        </View>
        </View>
      </View>

CSS 部分

 item: {
       marginVertical: moderateScale(7, 2),
       flexDirection: 'row'
    },
    itemIn: {
        marginLeft: 20
    },
    itemOut: {
       alignSelf: 'flex-end',
       marginRight: 20
    },
    balloon: {
       maxWidth: moderateScale(250, 2),
       paddingHorizontal: moderateScale(10, 2),
       paddingTop: moderateScale(5, 2),
       paddingBottom: moderateScale(7, 2),
       borderRadius: 20,
    },
    arrowContainer: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        zIndex: -1,
        flex: 1
    },
    arrowLeftContainer: {
        justifyContent: 'flex-end',
        alignItems: 'flex-start'
    },

    arrowRightContainer: {
        justifyContent: 'flex-end',
        alignItems: 'flex-end',
    },

    arrowLeft: {
        left: moderateScale(-6, 0.5),
    },

    arrowRight: {
        right:moderateScale(-6, 0.5),
    }

现在在不同的设备屏幕上缩放它对我来说只是反复试验。现在的输出对我来说已经足够好了。也许当我有时间时我会尝试改进当前的设计。

这就是它在 iOS 上的样子:

iPhone 7:
iPhone7

iPhone X:
enter image description here

现在在Android上不幸的是我无法让箭头的曲线出现。也许我做错了什么。这就是最终的样子。

像素2:
Pixel2

Nexus 6:
Nexus6

也许我们可以使用

flex
让箭头曲线在android上看起来不错。

万一有人制作了更好的版本。分享吧。 :)


2
投票

您无需使用 SVG 即可将其合并。这基本上是通过将

<View>
组件锚定在文本容器的角落来完成的。

<View style={styles.container}>
  <Text style={styles.text} key={index}>{item.text}</Text>
  <View style={styles.rightArrow} />
  <View style={styles.rightArrowOverlap} />
</View>

const styles = StyleSheet.create({
  container: {
    backgroundColor: "#0078fe",
    padding: 10,
    marginLeft: '45%',
    borderRadius: 20,
    marginTop: 5,
    marginRight: "5%",
    maxWidth: '50%',
    alignSelf: 'flex-end',
  },
  text: {
    fontSize: 16,
    color: "#fff",
  },
  rightArrow: {
    position: "absolute",
    backgroundColor: "#0078fe",
    width: 20,
    height: 25,
    bottom: 0,
    borderBottomLeftRadius: 25,
    right: -10,
  },
  rightArrowOverlap: {
    position: "absolute",
    backgroundColor: "#eeeeee",
    width: 20,
    height: 35,
    bottom: -6,
    borderBottomLeftRadius: 18,
    right: -20,
  },
});

borderRadius
maxWidth
margin
等属性值是任意的,可以根据您的需要进行更改。 您可以参考this文章,其中我对此进行了深入解释。
警告:将其与 FlatList 一起使用,因为观察到与其他函数(例如:地图)的渲染不一致


-1
投票

您可以使用react-native-gifted-chat库来制作完美的气泡 或者如果你想制作一个客户气泡,那么在平面列表渲染项中使用react-native的平面列表制作气泡 根据id发送者id或接收者id对齐气泡

© www.soinside.com 2019 - 2024. All rights reserved.