import React, { useMemo } from 'react' import { TextProps, StyleSheet, TextStyle, View, Text, ViewStyle } from 'react-native' import Svg, { Defs, LinearGradient as SvgLinearGradient, Stop, Text as SvgText } from 'react-native-svg' interface GradientTextProps extends Omit { colors: [string, string, ...string[]] start?: { x: number; y: number } end?: { x: number; y: number } style?: TextStyle } /** * 渐变文字组件(使用 SVG 实现,无需原生模块) * * @example * * 渐变文字 * */ export default function GradientText({ colors, start = { x: 0, y: 0 }, end = { x: 1, y: 0 }, style, children, ...textProps }: GradientTextProps) { const gradientId = useMemo(() => `gradient-${Math.random().toString(36).substr(2, 9)}`, []) // 从 style 中提取字体相关属性 const fontSize = (style?.fontSize as number) || 14 const fontWeight = style?.fontWeight || 'normal' const fontFamily = style?.fontFamily const textAlign = style?.textAlign || 'left' // 使用一个隐藏的 Text 来测量文字尺寸 const [textWidth, setTextWidth] = React.useState(0) const [textHeight, setTextHeight] = React.useState(fontSize * 1.2) // 计算渐变坐标(转换为百分比) const x1 = `${start.x * 100}%` const y1 = `${start.y * 100}%` const x2 = `${end.x * 100}%` const y2 = `${end.y * 100}%` // 计算文字位置 const textX = textAlign === 'center' ? (textWidth / 2) : textAlign === 'right' ? textWidth : 0 const textY = textHeight * 0.75 // 垂直位置,稍微调整以匹配基线 // 从 style 中提取 ViewStyle 兼容的属性 const containerStyle: ViewStyle = { ...(style?.margin !== undefined && { margin: style.margin }), ...(style?.marginTop !== undefined && { marginTop: style.marginTop }), ...(style?.marginBottom !== undefined && { marginBottom: style.marginBottom }), ...(style?.marginLeft !== undefined && { marginLeft: style.marginLeft }), ...(style?.marginRight !== undefined && { marginRight: style.marginRight }), ...(style?.marginHorizontal !== undefined && { marginHorizontal: style.marginHorizontal }), ...(style?.marginVertical !== undefined && { marginVertical: style.marginVertical }), } return ( {/* 隐藏的 Text 用于测量尺寸和占据空间 */} { const { width, height } = e.nativeEvent.layout setTextWidth(width || 0) setTextHeight(Math.max(height || fontSize * 1.2, fontSize * 1.2)) }} > {String(children)} {/* SVG 渐变文字 */} {textWidth > 0 && textHeight > 0 && ( {colors.map((color, index) => ( ))} {String(children)} )} ) } const styles = StyleSheet.create({ container: { backgroundColor: 'transparent', position: 'relative', }, measureText: { opacity: 0, includeFontPadding: false, // 确保文本占据空间 minHeight: 1, }, svgOverlay: { position: 'absolute', top: 0, left: 0, pointerEvents: 'none', }, })