fix: shadow

This commit is contained in:
郭文文 2026-01-21 19:02:09 +08:00
parent eadb745d63
commit 92578a7dce
3 changed files with 105 additions and 17 deletions

View File

@ -13,6 +13,7 @@ import { Canvas, Paragraph as SkiaParagraph, Path, Skia, useFonts } from '@shopi
import ParallelogramButton from '@/components/ParallelogramButton'
import ParallelogramGridItem from '@/components/ParallelogramGridItem'
import BannerSection from '@/components/BannerSection'
import ParallelogramShadow from '@/components/ParallelogramShadow'
import { useTemplateActions } from '@/hooks/actions/use-template-actions'
import { useTemplates } from '@/hooks/data'
import { useFavoriteTemplates } from '@/hooks/data/use-favorite-templates'
@ -582,26 +583,29 @@ const GooActions = observer<GooActionsProps>(function GooActions({ gooPoints, on
onClick={onAddGoo}
>
<Canvas style={{ position: 'absolute', inset: 0 }}>
{/* 白色主体 */}
<Path
path={Skia.Path.Make()
.moveTo(skewOffset+padding, padding)
.lineTo(width-padding, padding)
.lineTo(width - skewOffset-padding, height-padding)
.lineTo(padding, height-padding)
.moveTo(skewOffset + padding, padding)
.lineTo(width - padding, padding)
.lineTo(width - skewOffset - padding, height - padding)
.lineTo(padding, height - padding)
.close()}
color={Skia.Color('#FFFFFF')}
/>
{/* 黑色描边(适当加粗,避免底边过细) */}
<Path
path={Skia.Path.Make()
.moveTo(skewOffset+padding, padding)
.lineTo(width-padding, padding)
.lineTo(width - skewOffset-padding, height-padding)
.lineTo(padding, height-padding)
.moveTo(skewOffset + padding, padding)
.lineTo(width - padding, padding)
.lineTo(width - skewOffset - padding, height - padding)
.lineTo(padding, height - padding)
.close()}
color={Skia.Color('#000000')}
color={Skia.Color('#323232')}
style="stroke"
strokeWidth={1}
strokeWidth={2}
/>
<ParallelogramShadow height={height} padding={padding} skewOffset={skewOffset} width={width} />
</Canvas>
<Block className="absolute inset-0 flex-row items-center gap-[4px] pl-[12px]">
{isDev && isPolling && <Block className="ml-[4px] size-[6px] rounded-full bg-green-500" />}
@ -624,13 +628,13 @@ const GooActions = observer<GooActionsProps>(function GooActions({ gooPoints, on
.lineTo(addWidth - addSkewOffset - padding, addHeight - padding)
.lineTo(padding, addHeight - padding)
.close()}
color={Skia.Color('#000000')}
color={Skia.Color('#323232')}
style="stroke"
strokeWidth={1}
/>
</Canvas>
<Block className="absolute inset-0 items-center justify-center">
<Ionicons color="#000000" name="add" size={12} style={{ fontWeight: 'bold' }} />
<Ionicons color="#323232" name="add" size={12} style={{ fontWeight: 'bold' }} />
</Block>
</Block>
</Block>

View File

@ -15,6 +15,7 @@ import {
vec,
} from '@shopify/react-native-skia'
import { Block } from '@share/components'
import ParallelogramShadow from './ParallelogramShadow'
type MediaItem = {
id: string
@ -103,10 +104,14 @@ const ParallelogramGridItem = memo<Props>(function ParallelogramGridItem({
const labelHeight = 24
const cardHeight = itemWidth + labelHeight
// 预留给外部阴影的额外画布高度,避免阴影被裁剪
const shadowMargin = 4
// 平行四边形路径(只裁剪内容,不拉伸内容)
const skewOffset = 8
const padding = 2 // 四周内缩,避免描边被裁掉
// 外层(黑色)边框 & 裁剪路径
const parallelogramPath = useMemo(() => {
const p = Skia.Path.Make()
p.moveTo(skewOffset + padding, padding)
@ -181,8 +186,8 @@ const ParallelogramGridItem = memo<Props>(function ParallelogramGridItem({
height: cardHeight,
}}
>
<Block style={{ width: itemWidth, height: cardHeight, position: 'relative' }}>
<Canvas style={{ width: itemWidth, height: cardHeight, position: 'absolute' }}>
<Block style={{ width: itemWidth, height: cardHeight + shadowMargin, position: 'relative' }}>
<Canvas style={{ width: itemWidth, height: cardHeight + shadowMargin, position: 'absolute' }}>
<Group clip={parallelogramPath}>
{isVisible && displayImage && (
<SkiaImage
@ -215,7 +220,7 @@ const ParallelogramGridItem = memo<Props>(function ParallelogramGridItem({
y={itemWidth}
width={itemWidth}
height={1}
color="#000000"
color="#323232"
/>
)}
@ -238,11 +243,20 @@ const ParallelogramGridItem = memo<Props>(function ParallelogramGridItem({
)}
</Group>
{/* 先画阴影,再画描边,保证描边永远在最外层 */}
<ParallelogramShadow
height={cardHeight + shadowMargin}
baseHeight={cardHeight}
padding={padding}
skewOffset={skewOffset}
width={itemWidth}
/>
<Path
path={parallelogramPath}
style="stroke"
strokeWidth={isSelected ? 3 : 2}
color={isSelected ? '#FFE500' : '#000000'}
strokeWidth={3}
color={isSelected ? '#FFE500' : '#323232'}
/>
</Canvas>
</Block>

View File

@ -0,0 +1,70 @@
import React, { memo } from 'react'
import { Path, Skia } from '@shopify/react-native-skia'
export type ParallelogramShadowProps = {
width: number
height: number
skewOffset: number
padding: number
/** 平行四边形主体的高度(即底边所在的 y不传则等于 height */
baseHeight?: number
/** 阴影整体偏移量,默认 2 像素 */
offset?: number
/** 阴影颜色,默认 #323232 */
color?: string
/** 阴影线粗细,默认 3 像素 */
strokeWidth?: number
}
/**
* / +
*
*
* -
* - offset
*/
const ParallelogramShadow = memo<ParallelogramShadowProps>(function ParallelogramShadow({
width,
height,
skewOffset,
padding,
baseHeight,
offset = 2,
color = '#323232',
strokeWidth = 3,
}) {
const skiaColor = Skia.Color(color)
const h = baseHeight ?? height
// 只有在提供 baseHeight即有额外画布空间时才再往外多挪 1 像素,避免压住原始边框又不被裁剪
const extraOffsetY = baseHeight ? 1 : 0
return (
<>
{/* 底部阴影线 */}
<Path
path={Skia.Path.Make()
// 当有 baseHeight 时:相对于主体底边再向下挪 1px否则保持在 canvas 内部
.moveTo(padding + offset, h - padding + offset + extraOffsetY)
.lineTo(width - skewOffset - padding + offset, h - padding + offset + extraOffsetY)}
color={skiaColor}
style="stroke"
strokeWidth={strokeWidth}
/>
{/* 右侧阴影线 */}
<Path
path={Skia.Path.Make()
// 右侧阴影:仅在垂直方向多挪 1px水平方向仍保持在 canvas 内
.moveTo(width - skewOffset - padding + offset, h - padding + offset + extraOffsetY)
.lineTo(width - padding + offset, padding + offset + extraOffsetY)}
color={skiaColor}
style="stroke"
strokeWidth={strokeWidth}
/>
</>
)
})
ParallelogramShadow.displayName = 'ParallelogramShadow'
export default ParallelogramShadow