hover #6
@@ -9,6 +9,7 @@ import { View, TouchableOpacity, StyleSheet, ScrollView, Animated } from 'react-
|
|||||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||||
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
||||||
import Text from '../common/Text';
|
import Text from '../common/Text';
|
||||||
|
import { useHover } from '../../hooks/useHover';
|
||||||
|
|
||||||
type TabBarVariant = 'default' | 'pill' | 'segmented' | 'modern';
|
type TabBarVariant = 'default' | 'pill' | 'segmented' | 'modern';
|
||||||
|
|
||||||
@@ -22,6 +23,51 @@ interface TabBarProps {
|
|||||||
icons?: string[];
|
icons?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modern Tab 组件,支持悬停效果
|
||||||
|
interface ModernTabProps {
|
||||||
|
tab: string;
|
||||||
|
index: number;
|
||||||
|
isActive: boolean;
|
||||||
|
icon?: string;
|
||||||
|
onPress: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModernTab: React.FC<ModernTabProps> = ({ tab, index, isActive, icon, onPress }) => {
|
||||||
|
const { isHovered, hoverProps } = useHover();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[
|
||||||
|
styles.modernTab,
|
||||||
|
isActive && styles.modernTabActive,
|
||||||
|
isHovered && !isActive && styles.modernTabHovered,
|
||||||
|
]}
|
||||||
|
onPress={onPress}
|
||||||
|
activeOpacity={0.85}
|
||||||
|
{...hoverProps}
|
||||||
|
>
|
||||||
|
<View style={styles.modernTabContent}>
|
||||||
|
{icon && (
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
name={icon as any}
|
||||||
|
size={18}
|
||||||
|
color={isActive ? colors.primary.main : isHovered ? colors.primary.main : colors.text.secondary}
|
||||||
|
style={styles.modernTabIcon}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Text
|
||||||
|
variant="body"
|
||||||
|
color={isActive ? colors.primary.main : isHovered ? colors.primary.main : colors.text.secondary}
|
||||||
|
style={isActive ? [styles.modernTabText, styles.modernTabTextActive] : styles.modernTabText}
|
||||||
|
>
|
||||||
|
{tab}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
{isActive && <View style={styles.modernTabIndicator} />}
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const TabBar: React.FC<TabBarProps> = ({
|
const TabBar: React.FC<TabBarProps> = ({
|
||||||
tabs,
|
tabs,
|
||||||
activeIndex,
|
activeIndex,
|
||||||
@@ -38,31 +84,14 @@ const TabBar: React.FC<TabBarProps> = ({
|
|||||||
|
|
||||||
if (variant === 'modern') {
|
if (variant === 'modern') {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<ModernTab
|
||||||
key={index}
|
key={index}
|
||||||
style={[styles.modernTab, isActive && styles.modernTabActive]}
|
tab={tab}
|
||||||
|
index={index}
|
||||||
|
isActive={isActive}
|
||||||
|
icon={icon}
|
||||||
onPress={() => onTabChange(index)}
|
onPress={() => onTabChange(index)}
|
||||||
activeOpacity={0.85}
|
/>
|
||||||
>
|
|
||||||
<View style={styles.modernTabContent}>
|
|
||||||
{icon && (
|
|
||||||
<MaterialCommunityIcons
|
|
||||||
name={icon as any}
|
|
||||||
size={18}
|
|
||||||
color={isActive ? colors.primary.main : colors.text.secondary}
|
|
||||||
style={styles.modernTabIcon}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Text
|
|
||||||
variant="body"
|
|
||||||
color={isActive ? colors.primary.main : colors.text.secondary}
|
|
||||||
style={isActive ? [styles.modernTabText, styles.modernTabTextActive] : styles.modernTabText}
|
|
||||||
>
|
|
||||||
{tab}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
{isActive && <View style={styles.modernTabIndicator} />}
|
|
||||||
</TouchableOpacity>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +346,10 @@ const styles = StyleSheet.create({
|
|||||||
position: 'relative',
|
position: 'relative',
|
||||||
},
|
},
|
||||||
modernTabActive: {
|
modernTabActive: {
|
||||||
backgroundColor: colors.primary.main + '15', // 10% opacity
|
backgroundColor: colors.primary.main + '20', // 12% opacity
|
||||||
|
},
|
||||||
|
modernTabHovered: {
|
||||||
|
backgroundColor: colors.primary.main + '15', // 8% opacity
|
||||||
},
|
},
|
||||||
modernTabContent: {
|
modernTabContent: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|||||||
@@ -241,10 +241,10 @@ const styles = StyleSheet.create({
|
|||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
},
|
},
|
||||||
sidebarItemActive: {
|
sidebarItemActive: {
|
||||||
backgroundColor: `${colors.primary.main}15`,
|
backgroundColor: `${colors.primary.main}20`,
|
||||||
},
|
},
|
||||||
sidebarItemHovered: {
|
sidebarItemHovered: {
|
||||||
backgroundColor: `${colors.primary.main}08`,
|
backgroundColor: `${colors.primary.main}15`,
|
||||||
},
|
},
|
||||||
sidebarItemCollapsed: {
|
sidebarItemCollapsed: {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
|||||||
Reference in New Issue
Block a user