fix: ParallelogramGridItem
This commit is contained in:
parent
47f45bf85a
commit
79d8550987
|
|
@ -10,7 +10,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from '
|
|||
import { ActivityIndicator, RefreshControl, TextInput } from 'react-native'
|
||||
|
||||
import ParallelogramButton from '@/components/ParallelogramButton'
|
||||
|
||||
import ParallelogramGridItem from '@/components/ParallelogramGridItem'
|
||||
import BannerSection from '@/components/BannerSection'
|
||||
import { useTemplateActions } from '@/hooks/actions/use-template-actions'
|
||||
import { useTemplates } from '@/hooks/data'
|
||||
|
|
@ -20,7 +20,7 @@ import { screenWidth } from '@/utils'
|
|||
import { cn } from '@/utils/cn'
|
||||
|
||||
const CATEGORY_ID = process.env.EXPO_PUBLIC_INDEX_GROUP_ID
|
||||
const ITEM_WIDTH = Math.floor((screenWidth - 24 - 12 * 2) / 3)
|
||||
const ITEM_WIDTH = Math.floor((screenWidth - 10 * 2) / 3)
|
||||
|
||||
const PAGE_SIZE = 12
|
||||
|
||||
|
|
@ -416,11 +416,18 @@ const Index = observer(function Index() {
|
|||
|
||||
const renderItem = useCallback(
|
||||
({ item, index }: { item: MediaItem; index: number }) => (
|
||||
<GridItem
|
||||
// <GridItem
|
||||
// isSelected={selectedId === item.id}
|
||||
// item={item}
|
||||
// itemWidth={ITEM_WIDTH}
|
||||
// // 页面失焦时不渲染,减少内存占用
|
||||
// isVisible={isFocused && (index < 9 || visibleIdsRef.current.has(item.id))}
|
||||
// onSelect={() => setSelectedItem(item)}
|
||||
// />
|
||||
<ParallelogramGridItem
|
||||
isSelected={selectedId === item.id}
|
||||
item={item}
|
||||
itemWidth={ITEM_WIDTH}
|
||||
// 页面失焦时不渲染,减少内存占用
|
||||
isVisible={isFocused && (index < 9 || visibleIdsRef.current.has(item.id))}
|
||||
onSelect={() => setSelectedItem(item)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
import React, { memo, useMemo } from 'react'
|
||||
import { Pressable } from 'react-native'
|
||||
import {
|
||||
Canvas,
|
||||
Group,
|
||||
Image as SkiaImage,
|
||||
LinearGradient,
|
||||
Paragraph,
|
||||
Path,
|
||||
Rect,
|
||||
Skia,
|
||||
useFonts,
|
||||
useImage,
|
||||
vec,
|
||||
} from '@shopify/react-native-skia'
|
||||
|
||||
type MediaItem = {
|
||||
id: string
|
||||
url: string
|
||||
webpPreviewUrl?: string
|
||||
authorName?: string
|
||||
likeCount?: number
|
||||
title?: string
|
||||
}
|
||||
|
||||
type Props = {
|
||||
item: MediaItem
|
||||
isSelected: boolean
|
||||
itemWidth: number
|
||||
isVisible: boolean
|
||||
onSelect: () => void
|
||||
}
|
||||
|
||||
const ParallelogramGridItem = memo<Props>(function ParallelogramGridItem({
|
||||
item,
|
||||
isSelected,
|
||||
itemWidth,
|
||||
isVisible,
|
||||
onSelect,
|
||||
}) {
|
||||
const previewUrl = item.webpPreviewUrl || item.url || ''
|
||||
|
||||
// 整个卡片(图片区域 + 底部文字区域)的高度
|
||||
const labelHeight = 24
|
||||
const cardHeight = itemWidth + labelHeight
|
||||
|
||||
// 平行四边形路径(只裁剪内容,不拉伸内容),覆盖整张卡片
|
||||
const skewOffset = 8
|
||||
const padding = 2 // 四周内缩,避免描边被裁掉
|
||||
const parallelogramPath = useMemo(() => {
|
||||
const p = Skia.Path.Make()
|
||||
// 顶点全部在 Canvas 内部,留出 padding 空间
|
||||
p.moveTo(skewOffset + padding, padding)
|
||||
p.lineTo(itemWidth - padding, padding)
|
||||
p.lineTo(itemWidth - skewOffset - padding, cardHeight - padding)
|
||||
p.lineTo(padding, cardHeight - padding)
|
||||
p.close()
|
||||
return p
|
||||
}, [cardHeight, itemWidth])
|
||||
|
||||
const image = useImage(isVisible ? previewUrl : undefined)
|
||||
|
||||
// 字体管理,用于绘制作者和点赞数文本
|
||||
const fontMgr = useFonts({
|
||||
System: [],
|
||||
})
|
||||
|
||||
const authorParagraph = useMemo(() => {
|
||||
if (!fontMgr) return null
|
||||
const builder = Skia.ParagraphBuilder.Make(
|
||||
{
|
||||
textAlign: 0,
|
||||
},
|
||||
fontMgr,
|
||||
)
|
||||
|
||||
builder.pushStyle({
|
||||
color: Skia.Color('#323232'),
|
||||
fontSize: 10,
|
||||
fontFamilies: ['System'],
|
||||
fontStyle: { weight: 400 },
|
||||
})
|
||||
builder.addText(item.authorName || '未知作者')
|
||||
|
||||
const para = builder.build()
|
||||
para.layout(40)
|
||||
return para
|
||||
}, [fontMgr, item.authorName])
|
||||
|
||||
const likeParagraph = useMemo(() => {
|
||||
if (!fontMgr) return null
|
||||
const builder = Skia.ParagraphBuilder.Make(
|
||||
{
|
||||
textAlign: 0,
|
||||
},
|
||||
fontMgr,
|
||||
)
|
||||
|
||||
// 红色小心形符号
|
||||
builder.pushStyle({
|
||||
color: Skia.Color('#FF0000'),
|
||||
fontSize: 8,
|
||||
fontFamilies: ['System'],
|
||||
fontStyle: { weight: 900 },
|
||||
})
|
||||
builder.addText('❤ ')
|
||||
|
||||
// 白色数字
|
||||
builder.pushStyle({
|
||||
color: Skia.Color('#323232'),
|
||||
fontSize: 10,
|
||||
fontFamilies: ['System'],
|
||||
fontStyle: { weight: 400 },
|
||||
})
|
||||
builder.addText(String(item.likeCount ?? 0))
|
||||
|
||||
const para = builder.build()
|
||||
para.layout(40)
|
||||
return para
|
||||
}, [fontMgr, item.likeCount])
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
onPress={onSelect}
|
||||
style={{
|
||||
marginBottom: 12,
|
||||
width: itemWidth,
|
||||
height: cardHeight,
|
||||
}}
|
||||
>
|
||||
<Canvas style={{ width: itemWidth, height: cardHeight }}>
|
||||
{/* 整个卡片(图片 + 渐变 + 文本 + 黄色条)都被平行四边形裁剪 */}
|
||||
<Group clip={parallelogramPath}>
|
||||
{/* 上半部分:背景图片 */}
|
||||
{image && (
|
||||
<SkiaImage
|
||||
image={image}
|
||||
x={0}
|
||||
y={0}
|
||||
width={itemWidth}
|
||||
height={itemWidth}
|
||||
fit="cover"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 图片区域上的底部遮罩渐变 */}
|
||||
<LinearGradient
|
||||
start={vec(0, itemWidth)}
|
||||
end={vec(0, itemWidth * 0.6)}
|
||||
colors={['rgba(0,0,0,0.8)', 'transparent']}
|
||||
/>
|
||||
|
||||
{/* 底部黄色信息条(同样被平行四边形裁剪) */}
|
||||
<Rect
|
||||
x={0}
|
||||
y={itemWidth}
|
||||
width={itemWidth}
|
||||
height={labelHeight}
|
||||
color={isSelected ? '#FFE500' : '#FFFFFF'}
|
||||
/>
|
||||
|
||||
{/* 底部作者 + 喜欢数文本(在平行四边形内部,显示在黄色条上) */}
|
||||
{authorParagraph && (
|
||||
<Paragraph
|
||||
paragraph={authorParagraph}
|
||||
x={8}
|
||||
y={itemWidth + (labelHeight - 10) / 3}
|
||||
width={60}
|
||||
/>
|
||||
)}
|
||||
|
||||
{likeParagraph && (
|
||||
<Paragraph
|
||||
paragraph={likeParagraph}
|
||||
x={itemWidth - 32}
|
||||
y={itemWidth + (labelHeight - 10) / 3}
|
||||
width={40}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
|
||||
{/* 边框 */}
|
||||
<Path
|
||||
path={parallelogramPath}
|
||||
style="stroke"
|
||||
strokeWidth={isSelected ? 3 : 2}
|
||||
color={isSelected ? '#FFE500' : '#000000'}
|
||||
/>
|
||||
</Canvas>
|
||||
</Pressable>
|
||||
)
|
||||
})
|
||||
|
||||
export default ParallelogramGridItem
|
||||
Loading…
Reference in New Issue