React Native中如何实现卡片顶部反向圆角缺口?
React Native 实现顶部带自适应反向圆角缺口的红色卡片
核心思路
用react-native-svg绘制自定义形状的卡片背景,通过获取内部标题文本的宽度动态调整缺口大小,同时保证卡片的圆角和内容布局正常。
步骤1:安装依赖
首先安装react-native-svg:
npm install react-native-svg # 或者 yarn add react-native-svg
Expo项目直接安装即可;原生项目需额外执行pod install。
步骤2:实现自定义卡片组件
以下是完整可复用组件代码,支持自适应缺口、自定义内容:
import React, { useState, useRef } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import Svg, { Path } from 'react-native-svg'; const NotchedCard = ({ title, children, cardStyle, titleStyle, contentStyle }) => { const [titleWidth, setTitleWidth] = useState(0); const titleRef = useRef(null); // 获取标题文本宽度 const handleTextLayout = (event) => { const { width } = event.nativeEvent.layout; setTitleWidth(width); }; // 配置参数 const cardRadius = 16; const notchPadding = 12; const notchRadius = 8; const cardWidth = 340; const notchTotalWidth = titleWidth + notchPadding * 2; const notchStartX = (cardWidth - notchTotalWidth) / 2; const notchEndX = notchStartX + notchTotalWidth; return ( <View style={[styles.cardContainer, cardStyle]}> {/* 隐藏的标题,仅用于计算宽度 */} <Text ref={titleRef} onTextLayout={handleTextLayout} style={[styles.hiddenTitle, titleStyle]} > {title} </Text> {/* SVG绘制带缺口的红色卡片背景 */} <Svg width={cardWidth} height="100%" viewBox={`0 0 ${cardWidth} 100`} preserveAspectRatio="none" style={styles.svgBackground} > <Path d={` M ${cardRadius} 0 L ${notchStartX + notchRadius} 0 A ${notchRadius} ${notchRadius} 0 0 1 ${notchStartX} ${notchRadius} L ${notchStartX} ${notchRadius * 2} L ${notchEndX} ${notchRadius * 2} L ${notchEndX} ${notchRadius} A ${notchRadius} ${notchRadius} 0 0 1 ${notchEndX - notchRadius} 0 L ${cardWidth - cardRadius} 0 A ${cardRadius} ${cardRadius} 0 0 1 ${cardWidth} ${cardRadius} L ${cardWidth} 100 L 0 100 L 0 ${cardRadius} A ${cardRadius} ${cardRadius} 0 0 1 ${cardRadius} 0 `} fill="#ff3b30" /> </Svg> {/* 显示的标题,卡在缺口位置 */} <Text style={[styles.visibleTitle, titleStyle]}>{title}</Text> {/* 卡片内容区域 */} <View style={[styles.contentContainer, contentStyle]}> {children} </View> </View> ); }; const styles = StyleSheet.create({ cardContainer: { width: 340, alignSelf: 'center', marginVertical: 20, position: 'relative', overflow: 'hidden', }, hiddenTitle: { position: 'absolute', opacity: 0, left: 0, top: 0, }, svgBackground: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, }, visibleTitle: { position: 'absolute', top: -16, alignSelf: 'center', backgroundColor: '#fff', paddingHorizontal: 12, fontSize: 16, fontWeight: '600', color: '#333', }, contentContainer: { padding: 20, paddingTop: 24, }, }); export default NotchedCard;
关键细节说明
- 自适应缺口:通过
onTextLayout获取标题实际宽度,动态计算缺口的起始/结束位置,保证缺口随文字长度变化。 - 背景透明问题:SVG直接绘制红色卡片形状,无多余背景层,缺口区域不会出现不透明问题。
- 圆角效果:用SVG路径的
A命令绘制卡片四角和缺口的圆角,完全符合预期样式。 - 避免元素溢出:通过
position: relative和overflow: hidden限制容器范围,SVG的preserveAspectRatio="none"保证背景自适应卡片高度。
使用示例
import NotchedCard from './NotchedCard'; const App = () => { return ( <View style={{ flex: 1, backgroundColor: '#fff', paddingTop: 60 }}> <NotchedCard title="这是自适应长度的标题"> <Text style={{ color: '#fff', fontSize: 14 }}> 这里是卡片的内容区域,可以添加任意文本、组件等内容。 </Text> <Text style={{ color: '#fff', fontSize: 14, marginTop: 10 }}> 后续添加的内容也会正常显示在卡片内部。 </Text> </NotchedCard> </View> ); };
内容的提问来源于stack exchange,提问作者Hunter
相关产品推荐
相关产品推荐

