双端适配,web端的修改父容器和接口

This commit is contained in:
2026-03-29 02:34:13 +08:00
parent 3c071957ce
commit ebb0c003e3
16 changed files with 1419 additions and 226 deletions

View File

@@ -5,7 +5,7 @@
*/
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { View, TouchableOpacity, ActivityIndicator, Modal, Alert, Dimensions, StyleSheet, FlatList, ListRenderItem } from 'react-native';
import { View, TouchableOpacity, ActivityIndicator, Modal, Alert, Dimensions, StyleSheet, FlatList, ListRenderItem, ScrollView } from 'react-native';
import { Image as ExpoImage } from 'expo-image';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
@@ -18,11 +18,11 @@ import { useAppColors, spacing } from '../../../../theme';
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
// 表情尺寸配置
// 表情尺寸配置 - 固定宽度 40px使用 flex 布局
const EMOJI_SIZES = {
mobile: { size: 28, itemHeight: 52 },
tablet: { size: 32, itemHeight: 60 },
desktop: { size: 36, itemHeight: 68 },
mobile: { size: 24, itemWidth: 40, itemHeight: 40 },
tablet: { size: 26, itemWidth: 40, itemHeight: 40 },
desktop: { size: 28, itemWidth: 40, itemHeight: 40 },
};
// Tab 类型
@@ -62,29 +62,30 @@ export const EmojiPanel: React.FC<EmojiPanelProps> = ({
return EMOJI_SIZES.mobile;
}, [isWideScreen, isTablet]);
// 表情网格列数
const emojiColumns = useMemo(() => {
if (isWideScreen) return 10;
if (isTablet) return 9;
return 8;
}, [isWideScreen, isTablet]);
// 合并样式
// 合并样式 - 使用 flex 布局,每个表情固定 40px 宽度
const styles = useMemo(() => {
return StyleSheet.create({
...baseStyles,
emojiContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: spacing.sm,
},
emojiItem: {
...baseStyles.emojiItem,
width: `${100 / emojiColumns}%`,
height: emojiSize.itemHeight,
width: 40,
height: 40,
margin: 10,
alignItems: 'center',
justifyContent: 'center',
},
emojiText: {
...baseStyles.emojiText,
fontSize: emojiSize.size,
lineHeight: emojiSize.size + 6,
lineHeight: emojiSize.size + 4,
},
});
}, [emojiSize, emojiColumns, baseStyles]);
}, [emojiSize, baseStyles]);
// 加载自定义表情
const loadStickers = useCallback(async () => {
@@ -106,37 +107,26 @@ export const EmojiPanel: React.FC<EmojiPanelProps> = ({
}
}, [activeTab, loadStickers]);
const renderEmojiItem: ListRenderItem<string> = useCallback(({ item }) => (
<TouchableOpacity
style={styles.emojiItem}
onPress={() => onInsertEmoji(item)}
activeOpacity={0.7}
>
<Text style={styles.emojiText}>{item}</Text>
</TouchableOpacity>
), [styles.emojiItem, styles.emojiText, onInsertEmoji]);
// 渲染 Emoji 面板(使用 FlatList 虚拟化,降低首次打开卡顿)
// 渲染 Emoji 面板(使用 flex 布局,每个表情固定 40px 宽度)
const renderEmojiPanel = () => (
<FlatList
data={EMOJIS}
key={emojiColumns}
numColumns={emojiColumns}
keyExtractor={(item, index) => `${item}-${index}`}
renderItem={renderEmojiItem}
contentContainerStyle={styles.emojiGrid}
showsVerticalScrollIndicator={false}
<ScrollView
contentContainerStyle={styles.emojiContainer}
showsVerticalScrollIndicator={true}
keyboardShouldPersistTaps="handled"
initialNumToRender={emojiColumns * 4}
maxToRenderPerBatch={emojiColumns * 4}
windowSize={7}
removeClippedSubviews={true}
getItemLayout={(_, index) => ({
length: emojiSize.itemHeight,
offset: emojiSize.itemHeight * Math.floor(index / emojiColumns),
index,
})}
/>
>
{EMOJIS.map((emoji, index) => (
<TouchableOpacity
key={`${emoji}-${index}`}
style={styles.emojiItem}
onPress={() => onInsertEmoji(emoji)}
activeOpacity={0.7}
>
<Text style={styles.emojiText}>{emoji}</Text>
</TouchableOpacity>
))}
</ScrollView>
);
// 添加表情(从相册选择)