fix(ui): adjust keyboard handling and prevent duplicate view recording
- Fix keyboard avoidance logic in PostDetailScreen and ChatScreen by applying manual keyboard height offsets only on Android, preventing double padding on iOS. - Prevent multiple view recording calls in TradeDetailScreen by using a ref to track if the view has already been recorded.
This commit is contained in:
@@ -47,6 +47,8 @@ interface PostMentionInputProps {
|
|||||||
minHeight?: number;
|
minHeight?: number;
|
||||||
autoExpand?: boolean;
|
autoExpand?: boolean;
|
||||||
onPostRefPasted?: (postId: string, title: string) => void;
|
onPostRefPasted?: (postId: string, title: string) => void;
|
||||||
|
onSubmitEditing?: () => void;
|
||||||
|
returnKeyType?: 'default' | 'send' | 'done';
|
||||||
}
|
}
|
||||||
|
|
||||||
const PostMentionInput: React.FC<PostMentionInputProps> = ({
|
const PostMentionInput: React.FC<PostMentionInputProps> = ({
|
||||||
@@ -59,6 +61,8 @@ const PostMentionInput: React.FC<PostMentionInputProps> = ({
|
|||||||
minHeight = 100,
|
minHeight = 100,
|
||||||
autoExpand = false,
|
autoExpand = false,
|
||||||
onPostRefPasted,
|
onPostRefPasted,
|
||||||
|
onSubmitEditing,
|
||||||
|
returnKeyType = 'default',
|
||||||
}) => {
|
}) => {
|
||||||
const colors = useAppColors();
|
const colors = useAppColors();
|
||||||
const currentUser = useAuthStore(s => s.currentUser);
|
const currentUser = useAuthStore(s => s.currentUser);
|
||||||
@@ -281,6 +285,9 @@ const PostMentionInput: React.FC<PostMentionInputProps> = ({
|
|||||||
multiline
|
multiline
|
||||||
textAlignVertical="top"
|
textAlignVertical="top"
|
||||||
scrollEnabled={!autoExpand}
|
scrollEnabled={!autoExpand}
|
||||||
|
returnKeyType={returnKeyType}
|
||||||
|
onSubmitEditing={onSubmitEditing}
|
||||||
|
blurOnSubmit={false}
|
||||||
style={[
|
style={[
|
||||||
styles.input,
|
styles.input,
|
||||||
autoExpand && styles.inputAutoExpand,
|
autoExpand && styles.inputAutoExpand,
|
||||||
|
|||||||
@@ -1401,7 +1401,7 @@ export const PostDetailScreen: React.FC = () => {
|
|||||||
{
|
{
|
||||||
paddingHorizontal: responsivePadding,
|
paddingHorizontal: responsivePadding,
|
||||||
paddingVertical: responsiveGap,
|
paddingVertical: responsiveGap,
|
||||||
paddingBottom: keyboardHeight + responsiveGap + insets.bottom,
|
paddingBottom: (Platform.OS === 'android' ? keyboardHeight : 0) + responsiveGap + insets.bottom,
|
||||||
}
|
}
|
||||||
]}>
|
]}>
|
||||||
{/* 回复提示 */}
|
{/* 回复提示 */}
|
||||||
@@ -1486,6 +1486,8 @@ export const PostDetailScreen: React.FC = () => {
|
|||||||
minHeight={60}
|
minHeight={60}
|
||||||
autoExpand
|
autoExpand
|
||||||
style={styles.expandedTextInput}
|
style={styles.expandedTextInput}
|
||||||
|
returnKeyType="send"
|
||||||
|
onSubmitEditing={handleSendComment}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Image preview */}
|
{/* Image preview */}
|
||||||
|
|||||||
@@ -545,7 +545,8 @@ export const ChatScreen: React.FC<ChatScreenProps> = (props) => {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 底部区域:输入框 + 面板 */}
|
{/* 底部区域:输入框 + 面板 */}
|
||||||
<View style={{ marginBottom: keyboardHeight > 0 ? keyboardHeight : 0 }}>
|
{/* iOS 由外层 KeyboardAvoidingView(behavior=padding) 处理键盘避让;Android 需要手动推起 */}
|
||||||
|
<View style={{ marginBottom: Platform.OS === 'android' && keyboardHeight > 0 ? keyboardHeight : 0 }}>
|
||||||
{/* 输入框区域 */}
|
{/* 输入框区域 */}
|
||||||
<View
|
<View
|
||||||
style={[inputWrapperStyle, insets.bottom > 0 && { paddingBottom: insets.bottom }]}
|
style={[inputWrapperStyle, insets.bottom > 0 && { paddingBottom: insets.bottom }]}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
@@ -519,6 +519,7 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) {
|
|||||||
const [item, setItem] = useState<TradeItemDetailDTO | null>(null);
|
const [item, setItem] = useState<TradeItemDetailDTO | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [manageModalVisible, setManageModalVisible] = useState(false);
|
const [manageModalVisible, setManageModalVisible] = useState(false);
|
||||||
|
const hasRecordedView = useRef(false);
|
||||||
const [showImageModal, setShowImageModal] = useState(false);
|
const [showImageModal, setShowImageModal] = useState(false);
|
||||||
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
|
const [selectedImageIndex, setSelectedImageIndex] = useState(0);
|
||||||
|
|
||||||
@@ -548,7 +549,8 @@ export function TradeDetailScreen({ tradeId }: TradeDetailScreenProps) {
|
|||||||
}, [fetchItem]);
|
}, [fetchItem]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tradeId) {
|
if (tradeId && !hasRecordedView.current) {
|
||||||
|
hasRecordedView.current = true;
|
||||||
tradeService.recordView(tradeId).catch(() => {});
|
tradeService.recordView(tradeId).catch(() => {});
|
||||||
}
|
}
|
||||||
}, [tradeId]);
|
}, [tradeId]);
|
||||||
|
|||||||
Reference in New Issue
Block a user