feat: 更新心情编辑页面,优化心情描述输入框,增加日记标题和副标题,调整样式和布局,提升用户体验;修改MoodIntensitySlider组件,优化滑块样式和交互效果

This commit is contained in:
2025-09-05 22:56:00 +08:00
parent c37c3a16b1
commit 8d6a848918
2 changed files with 170 additions and 134 deletions

View File

@@ -39,10 +39,11 @@ export default function MoodIntensitySlider({
width = 320,
height = 16, // 更粗的进度条
}: MoodIntensitySliderProps) {
const thumbSize = 32; // 合适的触摸区域
const translateX = useSharedValue(0);
const sliderWidth = width - 40; // 减去thumb的宽度
const thumbSize = 36; // 更大的thumb
const isDragging = useSharedValue(0);
const sliderWidth = width - thumbSize; // thumb中心移动的有效范围
// 计算初始位置
React.useEffect(() => {
const initialPosition = ((value - min) / (max - min)) * sliderWidth;
@@ -60,16 +61,17 @@ export default function MoodIntensitySlider({
onStart: (_, context) => {
context.startX = translateX.value;
context.lastValue = value;
isDragging.value = withSpring(1);
runOnJS(triggerHaptics)();
},
onActive: (event, context) => {
const newX = context.startX + event.translationX;
const clampedX = Math.max(0, Math.min(sliderWidth, newX));
translateX.value = clampedX;
// 计算当前值
const currentValue = Math.round((clampedX / sliderWidth) * (max - min) + min);
// 当值改变时触发震动和回调
if (currentValue !== context.lastValue) {
context.lastValue = currentValue;
@@ -81,28 +83,52 @@ export default function MoodIntensitySlider({
// 计算最终值并吸附到最近的步长
const currentValue = Math.round((translateX.value / sliderWidth) * (max - min) + min);
const snapPosition = ((currentValue - min) / (max - min)) * sliderWidth;
translateX.value = withSpring(snapPosition);
isDragging.value = withSpring(0);
runOnJS(triggerHaptics)();
runOnJS(onValueChange)(currentValue);
},
});
const thumbStyle = useAnimatedStyle(() => {
const scale = interpolate(
const positionScale = interpolate(
translateX.value,
[0, sliderWidth],
[1, 1.05]
[1, 1.1]
);
const dragScale = interpolate(
isDragging.value,
[0, 1],
[1, 1.2]
);
const finalScale = positionScale * dragScale;
// 让thumb在滑动条中正确居中
const thumbPosition = translateX.value + thumbSize / 2;
return {
transform: [
{ translateX: translateX.value },
{ scale: withSpring(scale) }
{ translateX: thumbPosition },
{ scale: withSpring(finalScale) }
],
};
});
const thumbInnerStyle = useAnimatedStyle(() => {
const borderColor = interpolateColor(
isDragging.value,
[0, 1],
['#7a5af8', '#ff6b6b']
);
return {
borderColor: borderColor,
};
});
const progressStyle = useAnimatedStyle(() => {
const progressWidth = translateX.value + thumbSize / 2;
return {
@@ -146,7 +172,7 @@ export default function MoodIntensitySlider({
end={{ x: 1, y: 0 }}
/>
</View>
{/* 进度条 - 动态颜色 */}
<Animated.View style={[styles.progress, { height }, progressStyle, progressColorsStyle]}>
<LinearGradient
@@ -156,7 +182,7 @@ export default function MoodIntensitySlider({
end={{ x: 0, y: 0 }}
/>
</Animated.View>
{/* 可拖拽的thumb */}
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.thumb, { width: thumbSize, height: thumbSize }, thumbStyle]}>
@@ -166,17 +192,17 @@ export default function MoodIntensitySlider({
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
/> */}
<View style={styles.thumbInner} />
<Animated.View style={[styles.thumbInner, thumbInnerStyle]} />
</Animated.View>
</PanGestureHandler>
</View>
{/* 标签 */}
<View style={[styles.labelsContainer, { width: width }]}>
<Text style={styles.labelText}></Text>
<Text style={styles.labelText}></Text>
</View>
{/* 刻度 */}
<View style={[styles.scaleContainer, { width: width }]}>
{Array.from({ length: max - min + 1 }, (_, i) => i + min).map((num) => (
@@ -192,39 +218,38 @@ export default function MoodIntensitySlider({
const styles = StyleSheet.create({
container: {
alignItems: 'center',
paddingVertical: 16,
paddingTop: 8,
paddingBottom: 4,
},
sliderContainer: {
height: 50,
height: 10,
justifyContent: 'center',
position: 'relative',
paddingHorizontal: 20,
},
track: {
position: 'absolute',
left: 20,
right: 20,
borderRadius: 8,
left: 0,
right: 0,
borderRadius: 6,
overflow: 'hidden',
},
trackGradient: {
flex: 1,
borderRadius: 8,
borderRadius: 6,
},
progress: {
position: 'absolute',
left: 20,
borderRadius: 8,
left: 0,
borderRadius: 6,
overflow: 'hidden',
},
progressGradient: {
flex: 1,
borderRadius: 8,
borderRadius: 6,
},
thumb: {
position: 'absolute',
left: 22,
elevation: 6,
left: 0,
overflow: 'hidden',
},
thumbGradient: {
@@ -234,14 +259,11 @@ const styles = StyleSheet.create({
},
thumbInner: {
width: 16,
height: 32,
height: 28,
borderRadius: 8,
backgroundColor: '#ffffff',
shadowColor: '#ffffff',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.3,
shadowRadius: 2,
elevation: 2,
borderWidth: 2,
borderColor: '#7a5af8',
},
valueContainer: {
marginTop: 20,
@@ -266,33 +288,31 @@ const styles = StyleSheet.create({
labelsContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 8,
paddingHorizontal: 20,
marginTop: 6,
},
labelText: {
fontSize: 14,
fontSize: 12,
color: '#5d6676',
fontWeight: '600',
fontWeight: '500',
},
scaleContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 16,
paddingHorizontal: 20,
marginTop: 12,
},
scaleItem: {
alignItems: 'center',
flex: 1,
},
scaleMark: {
width: 2,
height: 10,
width: 1.5,
height: 8,
backgroundColor: '#e5e7eb',
borderRadius: 1,
borderRadius: 0.75,
},
scaleMarkActive: {
backgroundColor: '#7a5af8',
width: 3,
height: 12,
width: 2,
height: 10,
},
});