116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
import React, { memo, useMemo } from 'react'
|
||
import { Canvas, Group, Path, Skia } from '@shopify/react-native-skia'
|
||
import ParallelogramShadow from './ParallelogramShadow'
|
||
|
||
export type ParallelogramShapeProps = {
|
||
/** 宽度 */
|
||
width: number
|
||
/** 高度 */
|
||
height: number
|
||
/** 填充颜色 */
|
||
fillColor?: string
|
||
/** 描边颜色,默认 #323232 */
|
||
strokeColor?: string
|
||
/** 描边宽度,默认 3 */
|
||
strokeWidth?: number
|
||
/** 内边距,默认 2 */
|
||
padding?: number
|
||
/** 倾斜偏移量,默认 8(统一所有平行四边形的倾斜角度) */
|
||
skewOffset?: number
|
||
/** 是否显示阴影,默认 true */
|
||
showShadow?: boolean
|
||
/** 阴影颜色,默认 #323232 */
|
||
shadowColor?: string
|
||
/** 阴影偏移量,默认 2 */
|
||
shadowOffset?: number
|
||
/** 阴影线粗细,默认 3 */
|
||
shadowStrokeWidth?: number
|
||
/** 平行四边形主体的高度(用于阴影计算),不传则等于 height */
|
||
baseHeight?: number
|
||
/** Canvas 样式 */
|
||
canvasStyle?: any
|
||
/** 子元素(内容,放在 Canvas 外部) */
|
||
children?: React.ReactNode
|
||
/** 在 Canvas 内渲染的自定义内容(Skia 组件) */
|
||
renderContent?: () => React.ReactNode
|
||
}
|
||
|
||
/**
|
||
* 通用平行四边形形状组件
|
||
*
|
||
* 统一特性:
|
||
* - 所有平行四边形的倾斜角度一致(skewOffset = 8)
|
||
* - 所有平行四边形都有右侧阴影和下侧阴影
|
||
* - 统一的描边样式(黑色,宽度 3)
|
||
*/
|
||
const ParallelogramShape = memo<ParallelogramShapeProps>(function ParallelogramShape({
|
||
width,
|
||
height,
|
||
fillColor = '#FFFFFF',
|
||
strokeColor = '#323232',
|
||
strokeWidth = 3,
|
||
padding = 2,
|
||
skewOffset = 8,
|
||
showShadow = true,
|
||
shadowColor = '#323232',
|
||
shadowOffset = 2,
|
||
shadowStrokeWidth = 3,
|
||
baseHeight,
|
||
canvasStyle,
|
||
children,
|
||
renderContent,
|
||
}) {
|
||
// 创建平行四边形路径
|
||
const parallelogramPath = useMemo(() => {
|
||
const path = Skia.Path.Make()
|
||
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 skiaFillColor = Skia.Color(fillColor)
|
||
const skiaStrokeColor = Skia.Color(strokeColor)
|
||
|
||
return (
|
||
<>
|
||
<Canvas style={[{ position: 'absolute', inset: 0 }, canvasStyle]}>
|
||
{/* 填充 - 平行四边形主体 */}
|
||
<Path path={parallelogramPath} color={skiaFillColor} />
|
||
|
||
{/* 描边 - 平行四边形边框 */}
|
||
<Path
|
||
path={parallelogramPath}
|
||
color={skiaStrokeColor}
|
||
style="stroke"
|
||
strokeWidth={strokeWidth}
|
||
/>
|
||
|
||
{/* 阴影 - 右侧和下侧硬阴影 */}
|
||
{showShadow && (
|
||
<ParallelogramShadow
|
||
width={width}
|
||
height={height}
|
||
baseHeight={baseHeight}
|
||
padding={padding}
|
||
skewOffset={skewOffset}
|
||
offset={shadowOffset}
|
||
color={shadowColor}
|
||
strokeWidth={shadowStrokeWidth}
|
||
/>
|
||
)}
|
||
{/* 自定义内容(在 Canvas 内渲染) */}
|
||
{renderContent && renderContent()}
|
||
</Canvas>
|
||
{/* 内容区域(在 Canvas 外部) */}
|
||
{children}
|
||
</>
|
||
)
|
||
})
|
||
|
||
ParallelogramShape.displayName = 'ParallelogramShape'
|
||
|
||
export default ParallelogramShape
|