import React, { memo, useMemo } from 'react' import { Pressable } from 'react-native' import { Canvas, Group, Paragraph, Path, Skia, useFonts } from '@shopify/react-native-skia' export type ParallelogramButtonProps = { label: string state: string isActive: boolean onPress: () => void width: number height: number } const ParallelogramButton = memo(function ParallelogramButton({ label, state, isActive, onPress, width, height, }) { const fontMgr = useFonts({ System: [], }) // 创建英文 state 标签段落(白色字体,黑色描边,字重 700,激活时 #FAE307,未激活时白色) const stateParagraph = useMemo(() => { if (!fontMgr) return null const para = Skia.ParagraphBuilder.Make({}, fontMgr) .pushStyle({ color: isActive ? Skia.Color('#FAE307') : Skia.Color('#FFFFFF'), fontSize: 7, fontFamilies: ['System'], fontStyle: { weight: 700 }, shadows: [ // 黑色描边效果(略微偏移,避免过粗) { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -0.5, y: -0.5 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0.5, y: -0.5 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -0.5, y: 0.5 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0.5, y: 0.5 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -0.5, y: 0 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0.5, y: 0 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0, y: -0.5 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0, y: 0.5 } }, ], }) .addText(state) .build() para.layout(40) return para }, [fontMgr, state, isActive]) // 创建白色字体带黑色描边的中文文本段落 const paragraph = useMemo(() => { if (!fontMgr) return null const para = Skia.ParagraphBuilder.Make({}, fontMgr) .pushStyle({ color: Skia.Color('#FFFFFF'), fontSize: 13, fontFamilies: ['System'], fontStyle: { weight: 900 }, shadows: [ { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -1, y: -1 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 1, y: -1 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -1, y: 1 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 1, y: 1 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: -1, y: 0 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 1, y: 0 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0, y: -1 } }, { color: Skia.Color('#000000'), blurRadius: 0, offset: { x: 0, y: 1 } }, ], }) .addText(label) .build() para.layout(width - 12) // 减去左右 padding return para }, [fontMgr, label, width]) const skewOffset = 8 // 倾斜偏移量(像素) const padding = 15 // 增加 padding,防止旋转后的文本被裁剪 // 创建平行四边形路径:只有左右边倾斜,上下边保持水平 const parallelogramPath = useMemo(() => { const path = Skia.Path.Make() // 四个顶点:左上、右上、右下、左下(加上 padding 偏移) path.moveTo(skewOffset + padding, padding) path.lineTo(width + padding, padding) path.lineTo(width - skewOffset + padding, height + padding) path.lineTo(padding, height + padding) path.close() return path }, [width, height, skewOffset, padding]) // 创建边框路径 const borderPath = useMemo(() => { const path = Skia.Path.Make() path.moveTo(skewOffset + padding + 1, padding + 1) path.lineTo(width + padding - 1, padding + 1) path.lineTo(width - skewOffset + padding - 1, height + padding - 1) path.lineTo(padding + 1, height + padding - 1) path.close() return path }, [width, height, skewOffset, padding]) // 计算实际画布尺寸(包含 padding) const canvasWidth = width + padding * 2 const canvasHeight = height + padding * 2 // 注意:布局占位仍然使用原始 width,避免改变 tab 间距 return ( {/* 背景 - 平行四边形 */} {/* 边框 - 平行四边形 */} {/* 英文 state 标签 - 左上角,以左下角为中心,逆时针旋转 15 度 */} {stateParagraph && (() => { const stateTextX = 8 + skewOffset / 2 + 10 + padding const stateTextY = 4 + padding const rotationAngle = (-15 * Math.PI) / 180 const centerX = padding const centerY = height + padding return ( ) })()} {/* 中文文本 - 以左下角为中心,逆时针旋转 15 度 */} {paragraph && (() => { const textX = 16 + skewOffset / 2 + 2 + padding const textY = height - paragraph.getHeight() + 1 + padding const rotationAngle = (-15 * Math.PI) / 180 const centerX = padding const centerY = height + padding return ( ) })()} ) }) ParallelogramButton.displayName = 'ParallelogramButton' export default ParallelogramButton