Files
digital-pilates/components/ui/InfoCard.tsx
richarjiang d9975813cb feat(medications): 添加药品图片预览功能并优化InfoCard组件
- 在药品详情页面集成 react-native-image-viewing 实现图片全屏预览
- 添加图片预览提示图标,提升用户交互体验
- 优化 InfoCard 组件渲染逻辑,简化代码结构
- 调整药品图片样式,增加圆角效果并优化尺寸比例
- 为可点击的 InfoCard 图标和箭头添加玻璃态效果支持
2025-11-11 14:40:26 +08:00

173 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;