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

@@ -199,28 +199,36 @@ export default function MoodEditScreen() {
onValueChange={handleIntensityChange}
min={1}
max={10}
width={320}
width={280}
height={12}
/>
</View>
{/* 心情描述 */}
{selectedMood && (
<View style={styles.descriptionSection}>
<Text style={styles.sectionTitle}></Text>
<TextInput
style={styles.descriptionInput}
placeholder="描述一下你的心情..."
placeholderTextColor="#777f8c"
value={description}
onChangeText={setDescription}
multiline
maxLength={200}
textAlignVertical="top"
/>
<Text style={styles.characterCount}>{description.length}/200</Text>
</View>
)}
<View style={styles.descriptionSection}>
<Text style={styles.sectionTitle}></Text>
<Text style={styles.diarySubtitle}></Text>
<TextInput
style={styles.descriptionInput}
placeholder={`今天的心情如何?
你经历过什么特别的事情吗?
有什么让你开心的事?
或者,有什么让你感到困扰?
写下你的感受,让这些时刻成为你珍贵的记忆...`}
placeholderTextColor="#a8a8a8"
value={description}
onChangeText={setDescription}
multiline
maxLength={1000}
textAlignVertical="top"
/>
<Text style={styles.characterCount}>{description.length}/1000</Text>
</View>
</ScrollView>
{/* 底部按钮 */}
@@ -242,7 +250,7 @@ export default function MoodEditScreen() {
onPress={handleDelete}
disabled={isDeleting}
>
<Ionicons name="trash-outline" size={24} color="#f95555" />
<Ionicons name="trash-outline" size={20} color="#f95555" />
</TouchableOpacity>
)}
</View>
@@ -265,21 +273,21 @@ const styles = StyleSheet.create({
},
decorativeCircle1: {
position: 'absolute',
top: 40,
right: 20,
width: 60,
height: 60,
borderRadius: 30,
top: 30,
right: 15,
width: 45,
height: 45,
borderRadius: 22.5,
backgroundColor: '#7a5af8',
opacity: 0.08,
opacity: 0.06,
},
decorativeCircle2: {
position: 'absolute',
bottom: -15,
left: -15,
width: 40,
height: 40,
borderRadius: 20,
bottom: -10,
left: -10,
width: 30,
height: 30,
borderRadius: 15,
backgroundColor: '#7a5af8',
opacity: 0.04,
},
@@ -292,38 +300,38 @@ const styles = StyleSheet.create({
},
dateSection: {
backgroundColor: 'rgba(255,255,255,0.95)',
margin: 16,
borderRadius: 20,
padding: 20,
margin: 12,
borderRadius: 16,
padding: 16,
alignItems: 'center',
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 6,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 4,
},
dateTitle: {
fontSize: 26,
fontWeight: '800',
fontSize: 20,
fontWeight: '700',
color: '#192126',
},
moodSection: {
backgroundColor: 'rgba(255,255,255,0.95)',
margin: 16,
margin: 12,
marginTop: 0,
borderRadius: 20,
padding: 20,
borderRadius: 16,
padding: 16,
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 6,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 4,
},
sectionTitle: {
fontSize: 20,
fontWeight: '700',
fontSize: 16,
fontWeight: '600',
color: '#192126',
marginBottom: 20,
marginBottom: 16,
},
moodOptions: {
flexDirection: 'row',
@@ -333,9 +341,9 @@ const styles = StyleSheet.create({
moodOption: {
width: '18%',
alignItems: 'center',
paddingVertical: 16,
marginBottom: 12,
borderRadius: 16,
paddingVertical: 12,
marginBottom: 8,
borderRadius: 12,
backgroundColor: 'rgba(122,90,248,0.05)',
borderWidth: 1,
borderColor: 'rgba(122,90,248,0.1)',
@@ -346,55 +354,63 @@ const styles = StyleSheet.create({
borderColor: '#7a5af8',
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 4,
shadowOpacity: 0.12,
shadowRadius: 3,
elevation: 2,
},
moodImage: {
width: 40,
height: 40,
marginBottom: 10,
width: 32,
height: 32,
marginBottom: 6,
},
moodLabel: {
fontSize: 14,
fontSize: 12,
color: '#192126',
fontWeight: '600',
fontWeight: '500',
},
intensitySection: {
backgroundColor: 'rgba(255,255,255,0.95)',
margin: 16,
margin: 12,
marginTop: 0,
borderRadius: 20,
padding: 20,
borderRadius: 16,
padding: 16,
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 6,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 4,
},
descriptionSection: {
backgroundColor: 'rgba(255,255,255,0.95)',
margin: 16,
margin: 12,
marginTop: 0,
borderRadius: 20,
padding: 20,
borderRadius: 16,
padding: 16,
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.1,
shadowRadius: 12,
elevation: 6,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 4,
},
diarySubtitle: {
fontSize: 13,
color: '#666',
fontWeight: '500',
marginBottom: 12,
lineHeight: 18,
},
descriptionInput: {
borderWidth: 1.5,
borderColor: 'rgba(122,90,248,0.2)',
borderRadius: 12,
padding: 16,
fontSize: 16,
minHeight: 100,
borderRadius: 10,
padding: 12,
fontSize: 14,
minHeight: 120,
textAlignVertical: 'top',
backgroundColor: 'rgba(122,90,248,0.02)',
color: '#192126',
lineHeight: 20,
},
characterCount: {
fontSize: 12,
@@ -404,9 +420,9 @@ const styles = StyleSheet.create({
fontWeight: '500',
},
footer: {
padding: 16,
padding: 12,
position: 'absolute',
bottom: 24,
bottom: 20,
right: 8,
},
buttonRow: {
@@ -416,24 +432,24 @@ const styles = StyleSheet.create({
},
saveButton: {
backgroundColor: '#7a5af8',
borderRadius: 12,
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 20,
alignItems: 'center',
marginLeft: 12,
marginLeft: 8,
shadowColor: '#7a5af8',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
elevation: 3,
shadowOpacity: 0.15,
shadowRadius: 3,
elevation: 2,
},
deleteIconButton: {
width: 36,
height: 36,
borderRadius: 18,
width: 32,
height: 32,
borderRadius: 16,
justifyContent: 'center',
alignItems: 'center',
marginLeft: 12,
marginLeft: 8,
},
deleteButton: {
backgroundColor: '#f95555',
@@ -454,7 +470,7 @@ const styles = StyleSheet.create({
},
saveButtonText: {
color: '#fff',
fontSize: 14,
fontSize: 13,
fontWeight: '600',
},
deleteButtonText: {

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,
},
});