fix(dm): Android scroll-to-bottom via scrollToOffset(999999)
scrollToEnd() unterschätzt Content-Höhe auf Android und stoppt
konsistent eine Message zu früh (verifiziert per adb-Screenshot).
scrollToOffset({offset:999999}) wird auf den echten Max-Wert geclampt
und landet immer am absoluten Ende der Liste.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
89391a807b
commit
bd8d5a3072
@ -79,6 +79,16 @@ export default function DmScreen() {
|
|||||||
const { userId } = useLocalSearchParams<{ userId: string }>();
|
const { userId } = useLocalSearchParams<{ userId: string }>();
|
||||||
|
|
||||||
const flatListRef = useRef<FlatListType<ChatMsg>>(null);
|
const flatListRef = useRef<FlatListType<ChatMsg>>(null);
|
||||||
|
|
||||||
|
// scrollToEnd() auf Android unterschätzt Content-Höhe und stoppt 1 Item
|
||||||
|
// zu früh. scrollToOffset(999999) wird auf den echten Max-Wert geclampt.
|
||||||
|
const scrollToBottom = useCallback((animated = false) => {
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
flatListRef.current?.scrollToOffset({ offset: 999999, animated });
|
||||||
|
} else {
|
||||||
|
flatListRef.current?.scrollToEnd({ animated });
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
const [messages, setMessages] = useState<ChatMsg[]>([]);
|
const [messages, setMessages] = useState<ChatMsg[]>([]);
|
||||||
const [partner, setPartner] = useState<DmHistoryResponse['partner'] | null>(null);
|
const [partner, setPartner] = useState<DmHistoryResponse['partner'] | null>(null);
|
||||||
const partnerRef = useRef<DmHistoryResponse['partner'] | null>(null);
|
const partnerRef = useRef<DmHistoryResponse['partner'] | null>(null);
|
||||||
@ -110,12 +120,12 @@ export default function DmScreen() {
|
|||||||
const show = Keyboard.addListener(showEvent, (e) => {
|
const show = Keyboard.addListener(showEvent, (e) => {
|
||||||
setKeyboardHeight(e.endCoordinates.height);
|
setKeyboardHeight(e.endCoordinates.height);
|
||||||
setKeyboardVisible(true);
|
setKeyboardVisible(true);
|
||||||
requestAnimationFrame(() => flatListRef.current?.scrollToEnd({ animated: false }));
|
requestAnimationFrame(() => scrollToBottom(false));
|
||||||
});
|
});
|
||||||
const hide = Keyboard.addListener(hideEvent, () => {
|
const hide = Keyboard.addListener(hideEvent, () => {
|
||||||
setKeyboardHeight(0);
|
setKeyboardHeight(0);
|
||||||
setKeyboardVisible(false);
|
setKeyboardVisible(false);
|
||||||
setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 50);
|
setTimeout(() => scrollToBottom(false), 50);
|
||||||
});
|
});
|
||||||
return () => { show.remove(); hide.remove(); };
|
return () => { show.remove(); hide.remove(); };
|
||||||
}, []);
|
}, []);
|
||||||
@ -170,9 +180,9 @@ export default function DmScreen() {
|
|||||||
setMessages(msgs);
|
setMessages(msgs);
|
||||||
// Dreistufiges Scroll-to-bottom: rAF + 100ms + 300ms deckt
|
// Dreistufiges Scroll-to-bottom: rAF + 100ms + 300ms deckt
|
||||||
// Fälle ab wo Bilder nachgeladen werden und Content-Höhe wächst.
|
// Fälle ab wo Bilder nachgeladen werden und Content-Höhe wächst.
|
||||||
requestAnimationFrame(() => flatListRef.current?.scrollToEnd({ animated: false }));
|
requestAnimationFrame(() => scrollToBottom(false));
|
||||||
setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 100);
|
setTimeout(() => scrollToBottom(false), 100);
|
||||||
setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 300);
|
setTimeout(() => scrollToBottom(false), 300);
|
||||||
return data;
|
return data;
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('[dm] history fetch failed:', err?.message ?? err);
|
console.error('[dm] history fetch failed:', err?.message ?? err);
|
||||||
@ -187,7 +197,7 @@ export default function DmScreen() {
|
|||||||
// Neue Nachricht (incoming Realtime oder outgoing send) → immer scrollen
|
// Neue Nachricht (incoming Realtime oder outgoing send) → immer scrollen
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (messages.length === 0) return;
|
if (messages.length === 0) return;
|
||||||
requestAnimationFrame(() => flatListRef.current?.scrollToEnd({ animated: true }));
|
requestAnimationFrame(() => scrollToBottom(true));
|
||||||
}, [messages.length]);
|
}, [messages.length]);
|
||||||
|
|
||||||
// Realtime: neue DMs vom Partner
|
// Realtime: neue DMs vom Partner
|
||||||
@ -545,8 +555,8 @@ export default function DmScreen() {
|
|||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
keyboardDismissMode="interactive"
|
keyboardDismissMode="interactive"
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: false })}
|
onContentSizeChange={() => scrollToBottom(false)}
|
||||||
onLayout={() => flatListRef.current?.scrollToEnd({ animated: false })}
|
onLayout={() => scrollToBottom(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user