- 在药品详情页面集成 react-native-image-viewing 实现图片全屏预览 - 添加图片预览提示图标,提升用户交互体验 - 优化 InfoCard 组件渲染逻辑,简化代码结构 - 调整药品图片样式,增加圆角效果并优化尺寸比例 - 为可点击的 InfoCard 图标和箭头添加玻璃态效果支持
173 lines
4.1 KiB
TypeScript
173 lines
4.1 KiB
TypeScript
import type { Colors } from '@/constants/Colors';
|
||
import { Ionicons } from '@expo/vector-icons';
|
||
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
||
import React from 'react';
|
||
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||
|
||
export interface InfoCardProps {
|
||
label: string;
|
||
value: string;
|
||
icon: keyof typeof Ionicons.glyphMap;
|
||
colors: (typeof Colors)[keyof typeof Colors];
|
||
onPress?: () => void;
|
||
clickable?: boolean;
|
||
glassEffectStyle?: 'clear' | 'regular';
|
||
tintColor?: string;
|
||
className?: string;
|
||
}
|
||
|
||
export const InfoCard: React.FC<InfoCardProps> = ({
|
||
label,
|
||
value,
|
||
icon,
|
||
colors,
|
||
onPress,
|
||
clickable = false,
|
||
glassEffectStyle = 'clear',
|
||
tintColor,
|
||
}) => {
|
||
const isGlassAvailable = isLiquidGlassAvailable();
|
||
|
||
// 渲染图标按钮 - 只在可点击时应用 GlassView
|
||
const renderIcon = () => {
|
||
if (clickable && isGlassAvailable) {
|
||
return (
|
||
<GlassView
|
||
style={styles.infoCardIcon}
|
||
glassEffectStyle={glassEffectStyle}
|
||
tintColor={tintColor || 'rgba(76, 110, 245, 0.2)'}
|
||
isInteractive={true}
|
||
>
|
||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||
</GlassView>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<View style={[
|
||
styles.infoCardIcon,
|
||
clickable && styles.clickableIconFallback
|
||
]}>
|
||
<Ionicons name={icon} size={16} color="#4C6EF5" />
|
||
</View>
|
||
);
|
||
};
|
||
|
||
// 渲染箭头 - 只在可点击时显示并应用 GlassView
|
||
const renderArrow = () => {
|
||
if (!clickable) return null;
|
||
|
||
if (isGlassAvailable) {
|
||
return (
|
||
<GlassView
|
||
style={styles.infoCardArrow}
|
||
glassEffectStyle={glassEffectStyle}
|
||
tintColor={tintColor || 'rgba(255, 255, 255, 0.3)'}
|
||
isInteractive={true}
|
||
>
|
||
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
|
||
</GlassView>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<View style={[styles.infoCardArrow, styles.arrowFallback]}>
|
||
<Ionicons name="chevron-forward" size={16} color={colors.textMuted} />
|
||
</View>
|
||
);
|
||
};
|
||
|
||
// 卡片内容
|
||
const cardContent = (
|
||
<View style={[
|
||
styles.infoCard,
|
||
{ backgroundColor: colors.surface || '#fff' }
|
||
]}>
|
||
{renderArrow()}
|
||
{renderIcon()}
|
||
<Text style={[styles.infoCardLabel, { color: colors.textSecondary }]}>{label}</Text>
|
||
<Text style={[styles.infoCardValue, { color: colors.text }]}>{value}</Text>
|
||
</View>
|
||
);
|
||
|
||
// 如果可点击且有onPress回调,使用TouchableOpacity包装
|
||
if (clickable && onPress) {
|
||
return (
|
||
<TouchableOpacity
|
||
style={styles.container}
|
||
onPress={onPress}
|
||
activeOpacity={0.7}
|
||
>
|
||
{cardContent}
|
||
</TouchableOpacity>
|
||
);
|
||
}
|
||
|
||
// 不可点击的版本
|
||
return (
|
||
<View style={styles.container}>
|
||
{cardContent}
|
||
</View>
|
||
);
|
||
};
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
},
|
||
infoCard: {
|
||
flex: 1,
|
||
borderRadius: 20,
|
||
padding: 16,
|
||
backgroundColor: '#fff',
|
||
gap: 6,
|
||
shadowColor: '#000',
|
||
shadowOpacity: 0.04,
|
||
shadowRadius: 8,
|
||
shadowOffset: { width: 0, height: 4 },
|
||
elevation: 2,
|
||
position: 'relative',
|
||
},
|
||
infoCardArrow: {
|
||
position: 'absolute',
|
||
top: 12,
|
||
right: 12,
|
||
zIndex: 1,
|
||
width: 24,
|
||
height: 24,
|
||
borderRadius: 12,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
overflow: 'hidden', // 保证玻璃边界圆角效果
|
||
},
|
||
arrowFallback: {
|
||
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(0, 0, 0, 0.1)',
|
||
},
|
||
infoCardIcon: {
|
||
width: 28,
|
||
height: 28,
|
||
borderRadius: 14,
|
||
backgroundColor: '#EEF1FF',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
overflow: 'hidden', // 保证玻璃边界圆角效果
|
||
},
|
||
clickableIconFallback: {
|
||
borderWidth: 1,
|
||
borderColor: 'rgba(76, 110, 245, 0.3)',
|
||
},
|
||
infoCardLabel: {
|
||
fontSize: 13,
|
||
color: '#6B7280',
|
||
marginTop: 8,
|
||
},
|
||
infoCardValue: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#1F2933',
|
||
},
|
||
});
|
||
|
||
export default InfoCard; |