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:
parent
9835f9ef18
commit
360310e99f
4 changed files with 22 additions and 26 deletions
2
app.json
2
app.json
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue