feat: 滚动条

This commit is contained in:
jinyaqiu 2025-07-25 20:32:43 +08:00
parent 254692d9f4
commit 66645b3b5a

View File

@ -6,7 +6,7 @@ import { ThemedText } from "@/components/ThemedText";
import { fetchApi } from "@/lib/server-api-util";
import { Message } from "@/types/ask";
import { router, useLocalSearchParams } from "expo-router";
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
Animated,
Keyboard,
@ -14,6 +14,7 @@ import {
Platform,
ScrollView,
StyleSheet,
TextInput,
TouchableOpacity,
View
} from 'react-native';
@ -38,14 +39,56 @@ export default function AskScreen() {
newSession: string;
}>();
// 处理滚动到底部
useEffect(() => {
// 处理滚动到底部 - 优化版本
const scrollToBottom = useCallback((animated = true) => {
if (scrollViewRef.current && !isHello) {
scrollViewRef.current.scrollToEnd({ animated: true });
// 使用更长的延迟确保内容渲染完成
setTimeout(() => {
scrollViewRef.current?.scrollToEnd({ animated });
}, 150);
}
}, [userMessages, isHello]);
}, [isHello]);
// 处理路由参数
// 监听键盘显示/隐藏事件 - 增强版本
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
(e) => {
// 键盘显示时滚动到底部
setTimeout(() => {
scrollToBottom(true);
}, 100);
}
);
const keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
() => {
// 键盘隐藏时也滚动到底部(可选)
setTimeout(() => {
scrollToBottom(false);
}, 100);
}
);
return () => {
keyboardDidShowListener.remove();
keyboardDidHideListener.remove();
};
}, [scrollToBottom]);
// 处理消息变化时滚动 - 优化版本
useEffect(() => {
if (!isHello && userMessages.length > 0) {
// 消息变化时立即滚动到底部
const timer = setTimeout(() => {
scrollToBottom(true);
}, 50);
return () => clearTimeout(timer);
}
}, [userMessages.length, isHello, scrollToBottom]);
// 处理路由参数 - 优化版本
useEffect(() => {
if (sessionId) {
setConversationId(sessionId);
@ -81,17 +124,56 @@ export default function AskScreen() {
Animated.parallel([
Animated.timing(fadeAnim, {
toValue: 0,
duration: 1000,
duration: 300,
useNativeDriver: true,
}),
Animated.timing(fadeAnimChat, {
toValue: 1,
duration: 1000,
duration: 300,
useNativeDriver: true,
})
]).start();
]).start(() => {
// 动画完成后滚动到底部
setTimeout(() => {
scrollToBottom(false);
}, 50);
});
}
}, [isHello, fadeAnim, fadeAnimChat]);
}, [isHello, fadeAnim, fadeAnimChat, scrollToBottom]);
// 页面进入时的处理 - 新增
useEffect(() => {
if (!isHello) {
// 页面完全加载后滚动到底部
const timer = setTimeout(() => {
scrollToBottom(false);
}, 300);
return () => clearTimeout(timer);
}
}, [isHello, scrollToBottom]);
// 新增:页面获得焦点时处理
useEffect(() => {
// 页面进入时确保键盘关闭并滚动到底部
const timer = setTimeout(() => {
if (!isHello) {
// 让所有输入框失去焦点
try {
if (TextInput.State?.currentlyFocusedInput) {
const input = TextInput.State.currentlyFocusedInput();
if (input) input.blur();
}
} catch (error) {
console.log('失去焦点失败:', error);
}
// 滚动到底部
scrollToBottom(false);
}
}, 200);
return () => clearTimeout(timer);
}, [isHello, scrollToBottom]);
return (
<View style={[styles.container, { paddingTop: insets.top }]}>
@ -100,8 +182,17 @@ export default function AskScreen() {
<TouchableOpacity
style={styles.backButton}
onPress={() => {
router.push('/memo-list')
// 确保关闭键盘
try {
if (TextInput.State?.currentlyFocusedInput) {
const input = TextInput.State.currentlyFocusedInput();
if (input) input.blur();
}
} catch (error) {
console.log('失去焦点失败:', error);
}
Keyboard.dismiss();
router.push('/memo-list');
}}
>
<ReturnArrow />
@ -113,7 +204,6 @@ export default function AskScreen() {
<KeyboardAvoidingView
style={styles.keyboardAvoidingView}
behavior={Platform.OS === "ios" ? "padding" : "height"}
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 0}
enabled={!isHello}
>
<View style={styles.contentContainer}>
@ -138,13 +228,27 @@ export default function AskScreen() {
styles.absoluteView,
{
opacity: fadeAnimChat,
// 使用 pointerEvents 控制交互
pointerEvents: isHello ? 'none' : 'auto',
zIndex: 0
}
]}
>
<Chat userMessages={userMessages} sessionId={sessionId} setSelectedImages={setSelectedImages} selectedImages={selectedImages} />
<ScrollView
ref={scrollViewRef}
style={styles.chatContainer}
contentContainerStyle={styles.chatContentContainer}
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
onContentSizeChange={() => scrollToBottom(true)}
>
<Chat
userMessages={userMessages}
sessionId={sessionId}
setSelectedImages={setSelectedImages}
selectedImages={selectedImages}
/>
</ScrollView>
</Animated.View>
</View>
@ -210,16 +314,21 @@ const styles = StyleSheet.create({
contentContainer: {
flex: 1,
justifyContent: 'center',
paddingBottom: 20,
},
absoluteView: {
position: 'absolute', // 保持绝对定位
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'white',
},
chatContainer: {
flex: 1,
},
chatContentContainer: {
paddingBottom: 20,
},
inputContainer: {
padding: 16,
paddingBottom: 24,