feat: 优化图片加载和展示功能

- 新增 SmartImage 组件优化图片加载体验
- 新增 ImageGrid 组件支持多图布局展示
- 新增 imageHelper 工具函数
- 优化 PostCard 帖子卡片图片展示
- 优化消息页面 SegmentRenderer
- 优化日程页面 ScheduleScreen
- 优化上传服务 uploadService
This commit is contained in:
2026-03-15 02:25:55 +08:00
parent e9d42fdb01
commit 592167e667
8 changed files with 299 additions and 46 deletions

View File

@@ -2,6 +2,7 @@
* ImageGrid 图片网格组件
* 支持 1-9 张图片的智能布局
* 根据图片数量自动选择最佳展示方式
* 支持预览图优化
*/
import React, { useMemo, useCallback, useState, useEffect } from 'react';
@@ -16,6 +17,7 @@ import {
} from 'react-native';
import { SmartImage, ImageSource } from './SmartImage';
import { colors, spacing, borderRadius } from '../../theme';
import { getPreviewImageUrl, ImageDisplayMode } from '../../utils/imageHelper';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
@@ -69,6 +71,10 @@ export interface ImageGridProps {
onImagePress?: (images: ImageGridItem[], index: number) => void;
/** 测试ID */
testID?: string;
/** 显示模式 */
displayMode?: ImageDisplayMode;
/** 是否使用预览图 */
usePreview?: boolean;
}
/**
@@ -201,6 +207,7 @@ const SingleImageItem: React.FC<SingleImageItemProps> = ({
/**
* 图片网格组件
* 智能布局:根据图片数量自动选择最佳展示方式
* 支持预览图优化
*/
export const ImageGrid: React.FC<ImageGridProps> = ({
images,
@@ -214,6 +221,8 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
gridColumns = 3,
onImagePress,
testID,
displayMode = 'list',
usePreview = true,
}) => {
// 通过 onLayout 拿到容器实际宽度
const [containerWidth, setContainerWidth] = useState(0);
@@ -256,6 +265,12 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
const renderSingleImage = () => {
const image = displayImages[0];
if (!image) return null;
// 获取预览图 URL
const previewUrl = usePreview && displayMode
? getPreviewImageUrl(image as any, displayMode)
: (image.uri || image.url || '');
return (
<SingleImageItem
image={image}
@@ -271,27 +286,33 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
const renderHorizontal = () => {
return (
<View style={[styles.horizontalContainer, { gap }]}>
{displayImages.map((image, index) => (
<Pressable
key={image.id || index}
onPress={() => handleImagePress(index)}
style={[
styles.horizontalItem,
{
flex: 1,
aspectRatio: 1,
borderRadius: borderRadiusValue,
},
]}
>
<SmartImage
source={{ uri: image.uri || image.url, width: image.width, height: image.height }}
style={styles.fullSize}
resizeMode="cover"
borderRadius={borderRadiusValue}
/>
</Pressable>
))}
{displayImages.map((image, index) => {
const previewUrl = usePreview && displayMode
? getPreviewImageUrl(image as any, displayMode)
: (image.uri || image.url || '');
return (
<Pressable
key={image.id || index}
onPress={() => handleImagePress(index)}
style={[
styles.horizontalItem,
{
flex: 1,
aspectRatio: 1,
borderRadius: borderRadiusValue,
},
]}
>
<SmartImage
source={{ uri: previewUrl }}
style={styles.fullSize}
resizeMode="cover"
borderRadius={borderRadiusValue}
/>
</Pressable>
);
})}
</View>
);
};
@@ -303,6 +324,10 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
{displayImages.map((image, index) => {
const isLastVisible = index === displayImages.length - 1;
const showOverlay = isLastVisible && remainingCount > 0 && showMoreOverlay;
const previewUrl = usePreview && displayMode
? getPreviewImageUrl(image as any, displayMode)
: (image.uri || image.url || '');
return (
<Pressable
@@ -317,7 +342,7 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
]}
>
<SmartImage
source={{ uri: image.uri || image.url, width: image.width, height: image.height }}
source={{ uri: previewUrl }}
style={styles.fullSize}
resizeMode="cover"
borderRadius={borderRadiusValue}
@@ -361,6 +386,10 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
? image.width / image.height
: 1;
const height = itemWidth / aspectRatio;
const previewUrl = usePreview && displayMode
? getPreviewImageUrl(image as any, displayMode)
: (image.uri || image.url || '');
return (
<Pressable
@@ -376,7 +405,7 @@ export const ImageGrid: React.FC<ImageGridProps> = ({
]}
>
<SmartImage
source={{ uri: image.uri || image.url, width: image.width, height: image.height }}
source={{ uri: previewUrl }}
style={styles.fullSize}
resizeMode="cover"
borderRadius={borderRadiusValue}