按压变色效果实现
1. 使用 TouchableOpacity 基础实现
<TouchableOpacity
activeOpacity={0.7} // 按压时透明度变化
style={styles.button}
onPress={() => console.log('Pressed')}
>
<Text style={styles.buttonText}>点击按钮</Text>
</TouchableOpacity>
2. 高级按压变色效果(使用 useState 和 Animated)
import React, { useState } from 'react';
import { Animated, TouchableWithoutFeedback, Text } from 'react-native';
const ColorChangingButton = () => {
const [bgColor] = useState(new Animated.Value(0));
const handlePressIn = () => {
Animated.timing(bgColor, {
toValue: 1,
duration: 150,
useNativeDriver: false
}).start();
};
const handlePressOut = () => {
Animated.timing(bgColor, {
toValue: 0,
duration: 250,
useNativeDriver: false
}).start();
};
const colorInterpolation = bgColor.interpolate({
inputRange: [0, 1],
outputRange: ['#4CAF50', '#388E3C'] // 从浅绿到深绿
});
return (
<TouchableWithoutFeedback
onPressIn={handlePressIn}
onPressOut={handlePressOut}
>
<Animated.View style={[styles.button, { backgroundColor: colorInterpolation }]}>
<Text style={styles.buttonText}>动态变色按钮</Text>
</Animated.View>
</TouchableWithoutFeedback>
);
};
带特殊图标的按钮实现
1. 基础图标按钮
import { Ionicons } from '@expo/vector-icons';
<TouchableOpacity style={styles.iconButton}>
<Ionicons name="ios-heart" size={24} color="red" />
<Text style={styles.iconButtonText}>收藏</Text>
</TouchableOpacity>
2. 动态图标变化效果
import React, { useState } from 'react';
import { FontAwesome } from '@expo/vector-icons';
const LikeButton = () => {
const [liked, setLiked] = useState(false);
return (
<TouchableOpacity
style={styles.likeButton}
onPress={() => setLiked(!liked)}
>
<FontAwesome
name={liked ? "heart" : "heart-o"}
size={24}
color={liked ? "red" : "#333"}
/>
<Text style={styles.likeButtonText}>
{liked ? '已点赞' : '点赞'}
</Text>
</TouchableOpacity>
);
};
组合效果 - 按压变色+图标动画
import React, { useState } from 'react';
import { Animated, TouchableWithoutFeedback, Text, View } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
const AnimatedIconButton = () => {
const [scaleValue] = useState(new Animated.Value(1));
const [iconColor] = useState(new Animated.Value(0));
const handlePressIn = () => {
Animated.parallel([
Animated.spring(scaleValue, {
toValue: 0.95,
useNativeDriver: true
}),
Animated.timing(iconColor, {
toValue: 1,
duration: 150,
useNativeDriver: false
})
]).start();
};
const handlePressOut = () => {
Animated.parallel([
Animated.spring(scaleValue, {
toValue: 1,
friction: 3,
tension: 40,
useNativeDriver: true
}),
Animated.timing(iconColor, {
toValue: 0,
duration: 250,
useNativeDriver: false
})
]).start();
};
const colorInterpolation = iconColor.interpolate({
inputRange: [0, 1],
outputRange: ['#555', '#FF4081']
});
return (
<TouchableWithoutFeedback
onPressIn={handlePressIn}
onPressOut={handlePressOut}
>
<Animated.View style={[
styles.animatedButton,
{ transform: [{ scale: scaleValue }] }
]}>
<Animated.View style={{ color: colorInterpolation }}>
<MaterialIcons name="favorite" size={28} color={colorInterpolation} />
</Animated.View>
<Text style={styles.animatedButtonText}>喜欢</Text>
</Animated.View>
</TouchableWithoutFeedback>
);
};
样式定义
const styles = StyleSheet.create({
button: {
padding: 15,
borderRadius: 8,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#4CAF50',
margin: 10,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
iconButton: {
flexDirection: 'row',
alignItems: 'center',
padding: 12,
borderRadius: 6,
backgroundColor: '#F5F5F5',
margin: 10,
},
iconButtonText: {
marginLeft: 8,
fontSize: 16,
color: '#333',
},
likeButton: {
flexDirection: 'row',
alignItems: 'center',
padding: 10,
borderRadius: 20,
borderWidth: 1,
borderColor: '#DDD',
margin: 10,
},
likeButtonText: {
marginLeft: 6,
fontSize: 14,
},
animatedButton: {
flexDirection: 'row',
alignItems: 'center',
padding: 12,
borderRadius: 24,
backgroundColor: 'white',
margin: 10,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
animatedButtonText: {
marginLeft: 8,
fontSize: 16,
color: '#555',
},
});
技术要点总结
-
按压效果:
- 使用
TouchableOpacity
的activeOpacity
属性实现简单效果 - 使用
Animated
API 实现更复杂的颜色和尺寸变化
- 使用
-
图标集成:
- 使用
@expo/vector-icons
或其他图标库 - 根据按钮状态动态改变图标
- 使用
-
组合动画:
- 使用
Animated.parallel
同时运行多个动画 - 结合缩放、颜色变化和透明度效果
- 使用
-
性能优化:
- 尽可能使用
useNativeDriver: true
- 避免在动画中使用复杂的布局计算
- 尽可能使用
-
交互反馈:
- 提供清晰的视觉反馈增强用户体验
- 保持动画快速流畅(通常在200-300ms之间)