fix: replace KeyboardAvoidingView with manual keyboard padding (#6)

KeyboardAvoidingView does not work with edgeToEdgeEnabled on Android.
New approach: listen to Keyboard events, dynamically set spacer height
to actual keyboard height, and scrollToEnd when subtask input is focused.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
le king fu 2026-03-01 14:40:58 -05:00
parent 9835f9ef18
commit 360310e99f
4 changed files with 22 additions and 26 deletions

View file

@ -2,7 +2,7 @@
"expo": {
"name": "Simpl-Liste",
"slug": "simpl-liste",
"version": "1.2.1",
"version": "1.2.2",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "simplliste",

View file

@ -8,7 +8,6 @@ import {
useColorScheme,
Alert,
Platform,
KeyboardAvoidingView,
Keyboard,
} from 'react-native';
import { useRouter, useLocalSearchParams } from 'expo-router';
@ -83,16 +82,20 @@ export default function TaskDetailScreen() {
const [selectedListId, setSelectedListId] = useState<string>('');
const [saving, setSaving] = useState(false);
const scrollRef = useRef<ScrollView>(null);
const subtaskInputY = useRef(0);
const subtaskFocused = useRef(false);
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
const sub = Keyboard.addListener('keyboardDidShow', () => {
const showSub = Keyboard.addListener('keyboardDidShow', (e) => {
setKeyboardHeight(e.endCoordinates.height);
if (subtaskFocused.current) {
scrollRef.current?.scrollTo({ y: subtaskInputY.current - 80, animated: true });
setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 100);
}
});
return () => sub.remove();
const hideSub = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardHeight(0);
});
return () => { showSub.remove(); hideSub.remove(); };
}, []);
useEffect(() => {
@ -223,7 +226,6 @@ export default function TaskDetailScreen() {
</View>
</View>
<KeyboardAvoidingView className="flex-1" behavior="padding">
<ScrollView ref={scrollRef} className="flex-1 px-4 pt-4" keyboardShouldPersistTaps="handled">
{/* Title */}
<TextInput
@ -407,10 +409,7 @@ export default function TaskDetailScreen() {
))}
{/* Add subtask */}
<View
className="mt-2 flex-row items-center"
onLayout={(e) => { subtaskInputY.current = e.nativeEvent.layout.y; }}
>
<View className="mt-2 flex-row items-center">
<Plus size={18} color={colors.bleu.DEFAULT} />
<TextInput
value={newSubtask}
@ -425,9 +424,8 @@ export default function TaskDetailScreen() {
/>
</View>
<View className="h-80" />
<View style={{ height: keyboardHeight || 32 }} />
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}

View file

@ -7,7 +7,6 @@ import {
ScrollView,
useColorScheme,
Platform,
KeyboardAvoidingView,
Keyboard,
} from 'react-native';
import { useRouter, useLocalSearchParams } from 'expo-router';
@ -61,16 +60,20 @@ export default function NewTaskScreen() {
const [pendingSubtasks, setPendingSubtasks] = useState<string[]>([]);
const [newSubtask, setNewSubtask] = useState('');
const scrollRef = useRef<ScrollView>(null);
const subtaskInputY = useRef(0);
const subtaskFocused = useRef(false);
const [keyboardHeight, setKeyboardHeight] = useState(0);
useEffect(() => {
const sub = Keyboard.addListener('keyboardDidShow', () => {
const showSub = Keyboard.addListener('keyboardDidShow', (e) => {
setKeyboardHeight(e.endCoordinates.height);
if (subtaskFocused.current) {
scrollRef.current?.scrollTo({ y: subtaskInputY.current - 80, animated: true });
setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 100);
}
});
return () => sub.remove();
const hideSub = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardHeight(0);
});
return () => { showSub.remove(); hideSub.remove(); };
}, []);
useEffect(() => {
@ -150,7 +153,6 @@ export default function NewTaskScreen() {
</Pressable>
</View>
<KeyboardAvoidingView className="flex-1" behavior="padding">
<ScrollView ref={scrollRef} className="flex-1 px-4 pt-4" keyboardShouldPersistTaps="handled">
{/* Title */}
<TextInput
@ -377,10 +379,7 @@ export default function NewTaskScreen() {
))}
{/* Add subtask */}
<View
className="mt-2 flex-row items-center"
onLayout={(e) => { subtaskInputY.current = e.nativeEvent.layout.y; }}
>
<View className="mt-2 flex-row items-center">
<Plus size={18} color={colors.bleu.DEFAULT} />
<TextInput
value={newSubtask}
@ -395,9 +394,8 @@ export default function NewTaskScreen() {
/>
</View>
<View className="h-80" />
<View style={{ height: keyboardHeight || 32 }} />
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}

View file

@ -1,7 +1,7 @@
{
"name": "simpl-liste",
"main": "index.js",
"version": "1.2.1",
"version": "1.2.2",
"scripts": {
"start": "expo start",
"android": "expo start --android",