Skip to content

Dropdown Does Not Return to Original Position After Keyboard Dismiss #339

@JOMENMAR

Description

@JOMENMAR

When the keyboard opens, the dropdown is pushed up as expected. But once the keyboard is dismissed, the dropdown doesn’t return to its original position—it just stays higher up on the screen. The issue isn’t related to the margin animation or the dropdown’s open/close state. It seems like the component isn’t reacting properly to the keyboard hiding event. Tried listening to keyboardDidHide and triggering a reposition or animation manually, but it doesn’t help—nothing moves it back down.

It feels like the view doesn’t get notified that the keyboard’s gone, or it’s not re-rendering correctly based on the layout changes.

Code:

`import React, { useState, useRef, useCallback, useEffect } from 'react';
import { View, Image, ImageBackground, TextInput, TouchableOpacity, StyleSheet, Animated, Keyboard, Platform } from 'react-native';
import LottieView from 'lottie-react-native';
import { Dropdown } from 'react-native-element-dropdown';
import ModalNoWifi from './ModalNoWifi';
import MyText from './MyText';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { COLORS } from '../utils/colors';

const ImageView = ({
image,
bgLoad,
setBgLoad,
setActiveTimer,
isConnected,
setIsConnected,
setImage,
saveImage,
residuos,
name,
setName,
tipo,
setTipo,
color,
setColor,
cantidad,
setCantidad,
objects_shortV2,
addTrash,
}) => {
const [marginTop] = useState(new Animated.Value(15));

const dropdownRef = useRef(null);
const [dropdownOpen, setDropdownOpen] = useState(false);
const hasOpenedRef = useRef(false);


const animateMarginTop = (value) => {
    return new Promise((resolve) => {
        Animated.timing(marginTop, {
            toValue: value,
            duration: 1000,
            useNativeDriver: false,
        }).start(() => resolve());
    });
};

const handleDropdownOpen = useCallback(async () => {
    if (hasOpenedRef.current || dropdownOpen) return;

    hasOpenedRef.current = true;

    await animateMarginTop(115);
    dropdownRef.current?.open();
    setDropdownOpen(true);
}, []);

const handleDropdownClose = useCallback(async () => {
    await animateMarginTop(15);

    if (dropdownRef.current?.isOpen) {
        dropdownRef.current.close();
    }

    setDropdownOpen(false);
    hasOpenedRef.current = false;
}, []);

return (
    <View style={{ flex: 1, justifyContent: 'flex-end' }}>
        {bgLoad ? (
            <ImageBackground
                source={{ uri: image }}
                style={styles.background}
                resizeMode="cover"
                onLoad={() => setActiveTimer(true)}
            >
                <LottieView
                    autoPlay
                    speed={1}
                    loop
                    style={styles.lottieAnimationIA}
                    source={require('../../assets/animations/CargarIA.json')}
                />
            </ImageBackground>
        ) : (
            <ImageBackground
                source={{ uri: image }}
                style={styles.background}
                resizeMode="cover"
            >
                {!isConnected ? (
                    <ModalNoWifi
                        visible={!false}
                        onRetry={() => {
                            NetInfo.fetch().then(state => {
                                setIsConnected(state.isConnected);
                            });
                            setBgLoad(true);
                            setActiveTimer(false);
                        }}
                        onCancel={() => {
                            setImage(null);
                            setBgLoad(true);
                            setActiveTimer(false);
                        }}
                        onSaveForLater={() => {
                            saveImage();
                            setImage(null);
                            setBgLoad(true);
                            setActiveTimer(false);
                        }}
                    />
                ) : (
                    <View style={styles.containerIA}>
                        <MyText fontWeightParam={'medium'} style={{ marginLeft: 5, fontSize: 15 }}>
                            Objetos detectados en la imagen
                        </MyText>
                        <View style={styles.gridConteiner}>
                            <View style={styles.column1}>
                                <View style={styles.imageContainer}>
                                    <Image
                                        source={{ uri: image }}
                                        style={styles.imageTrash}
                                    />
                                </View>
                            </View>
                            <View style={styles.column2}>
                                <View style={styles.row1}>
                                    <View
                                        style={[styles.colorCircle, { backgroundColor: color }]}
                                    />
                                    <MyText fontWeightParam={'medium'} style={{ selfAlign: 'center' }}>
                                        {tipo}
                                    </MyText>
                                </View>
                                <View style={styles.row2}>
                                    <Dropdown
                                        ref={dropdownRef}
                                        style={styles.dropdown}
                                        data={residuos}
                                        mode='auto'
                                        labelField="label"
                                        valueField="value"
                                        value={name}
                                        search
                                        placeholder={
                                            <MyText fontWeightParam="regular" style={{ fontSize: 14, color: '#C6C6C6' }}>
                                                Elije tu residuo...
                                            </MyText>}
                                        searchPlaceholder="Buscar residuo..."
                                        dropdownPosition="bottom"
                                        inputSearchStyle={styles.searchContainer}
                                        selectedTextStyle={{ fontSize: 12 }}
                                        containerStyle={styles.dropdownContainer}
                                        onFocus={handleDropdownOpen}
                                        onBlur={handleDropdownClose}
                                        onChange={(item) => {
                                            setName(item.value);
                                            setTipo(item.tipo);
                                            setColor(item.color);
                                        }}
                                        autoScroll={false}
                                        renderItem={(item) => (
                                            <View style={styles.itemContainer}>
                                                <MyText style={[styles.itemText, { flex: 5 }]}>{item.label}</MyText>
                                                <View style={{ flex: 5, flexDirection: 'row', alignItems: 'flex-start' }}>
                                                    <View style={[
                                                        styles.colorCircle,
                                                        { backgroundColor: item.color || 'black' },
                                                    ]} />
                                                    <MyText style={styles.itemTipo}>{item.tipo}</MyText>
                                                </View>
                                            </View>
                                        )}
                                    />
                                    <TextInput
                                        defaultValue={'1'}
                                        value={cantidad}
                                        style={styles.numberInput}
                                        onChangeText={(t) => setCantidad(t)}
                                        keyboardType="numeric"
                                    />
                                </View>
                            </View>
                        </View>
                        <View style={{ alignItems: 'flex-end' }}>
                            <Animated.View style={{ alignItems: 'flex-end', marginTop }}>
                                <TouchableOpacity
                                    style={[styles.guardarButton]}
                                    accessibilityLabel="Guardar Residuo"
                                    onPress={() => {
                                        const selectedItem = objects_shortV2.find((obj) => obj.name === name);
                                        if (!selectedItem) return;

                                        const itemToSave = {
                                            ...selectedItem,
                                            quantity: Number(cantidad),
                                            observation: '',
                                            weight: 0,
                                        };
                                        addTrash(itemToSave);
                                        setCantidad('1');
                                        setBgLoad(true);
                                        setActiveTimer(false);
                                    }}
                                >
                                    <MaterialIcons name="save" size={20} color="white" />
                                    <MyText fontWeightParam={'regular'} style={{ color: 'white', marginLeft: 5 }}>
                                        Guardar
                                    </MyText>
                                </TouchableOpacity>
                            </Animated.View>
                        </View>
                    </View>
                )}
            </ImageBackground>
        )}
    </View>
);

};

const styles = StyleSheet.create({
background: {
flex: 1,
width: '100%',
height: '100%',
justifyContent: 'flex-end',
alignItems: 'center',
},
lottieAnimationIA: {
position: 'absolute',
alignSelf: 'center',
bottom: '40%',
width: 125,
height: 125,
},
containerIA: {
width: '100%',
paddingVertical: 15,
backgroundColor: 'white',
borderTopLeftRadius: 25,
borderTopRightRadius: 25,
paddingHorizontal: 15,
},
gridConteiner: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
marginTop: 10,
},
column1: {
width: '20%',
alignItems: 'center',
justifyContent: 'center',
},
column2: {
width: '80%',
flexDirection: 'column',
},
row1: {
flexDirection: 'row',
width: '100%',
alignItems: 'flex-start',
alignContent: 'center',
verticalAlign: 'bottom',
},
row2: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
},
imageContainer: {
flexDirection: "row",
overflow: "visible",
marginRight: 0,
alignItems: 'right',
paddingHorizontal: -25,
marginBottom: 5,
marginTop: 15,
},
imageTrash: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: -10,
borderWidth: 2,
borderColor: "#fff",
},
dropdown: {
borderWidth: 1,
borderColor: '#E0E0E0',
borderRadius: 10,
paddingHorizontal: 10,
backgroundColor: 'white',
flexGrow: 1,
paddingVertical: 5,
},
dropdownContainer: {
marginTop: 5,
borderRadius: 10,
backgroundColor: 'white',
elevation: 5,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 5,
},
searchContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 5,
backgroundColor: 'white',
margin: 10,
borderRadius: 5,
fontSize: 13,
},
itemContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 10,
paddingHorizontal: 15,
borderBottomWidth: 1,
borderColor: '#e0e0e0',
},
itemText: {
fontSize: 12,
flex: 1,
},
itemTipo: {
fontSize: 12,
textAlign: 'left',
},
colorCircle: {
borderWidth: 0.2,
borderColor: '#000000',
width: 15,
height: 15,
borderRadius: 7.5,
marginHorizontal: 10,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
numberInput: {
padding: 5,
width: '20%',
height: '100%',
textAlign: 'center',
alignSelf: 'center',
borderWidth: 1,
borderColor: '#E0E0E0',
borderRadius: 10,
backgroundColor: 'white',
marginLeft: 10,
fontSize: 18,
},
guardarButton: {
flexDirection: "row",
backgroundColor: COLORS.secondary,
borderRadius: 100,
marginBottom: 15,
paddingHorizontal: 20,
paddingVertical: 5,
justifyContent: "center",
},
});

export default ImageView;
`

Images

Image

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions