Animate.timing не работает с nativeEvent onLayout

Я пытаюсь анимировать поле просмотра, скользящее вниз до его фактической высоты. Во-первых, если максимальная высота представления, то есть высота, необходимая для просмотра всего содержимого, меньше 70, в анимации нет необходимости. Если максимальная высота больше 70, то я устанавливаю высоту описания на 70, и при нажатии на представление оно будет анимироваться до максимальной высоты. Это моя цель.

По какой-то причине у меня возникают проблемы с получением функцией onLayout необходимой высоты содержимого. Вот мой код:

function card() {

    const [expandedDescription, setexpandedDescription] = useState(false);
    const [descriptionHeight, setdescriptionHeight] = useState(new Animated.Value(0))
    const [layoutCount, setlayoutCount] = useState(0)
    const [maxContentHeight, setmaxContentHeight] = useState(0);

    const getContentHeight = (event:any) => {
        setmaxContentHeight(event.nativeEvent.layout.height);
        if(maxContentHeight < 70){
            setdescriptionHeight(new Animated.Value(maxContentHeight));
        }
        else{
            setdescriptionHeight(new Animated.Value(70));
        }
    }

    const toggle = () => {
        console.log(maxContentHeight);
        if(maxContentHeight > 70){
            Animated.timing(descriptionHeight, {
                toValue: expandedDescription ? descriptionHeight : maxContentHeight,
                duration: 300,
            }).start();
            setexpandedDescription(!expandedDescription);
        }
    }

    return (
        <View style={styles.cardContainer}>
            <Animated.View style={[styles.descriptionContainer, {height:descriptionHeight}]} onLayout={(event:any) => getContentHeight(event)} >
                <Text style={styles.descriptionHeaderText}>Description</Text>
                <TouchableOpacity onPress={() => toggle()}>
                    <Text style={styles.descriptionText}>Lorem ipsum dolor sit amet, consectetur 
                        adipiscing elit. Aenean bibendum tincidfffffffffunt libero, nec luctus dolor consequat 
                        quis. Phasellus portalike elephants and had to work hard to earn their while chicken 
                    </Text>
                </TouchableOpacity>
            </Animated.View>
        </View>
    )
}

const styles = StyleSheet.create({
    cardContainer: {
        width: '95%',
        marginBottom: 10,
        backgroundColor: '#ffffff',
        borderRadius:25,
        height: 'auto',
        alignItems:'center',
        paddingLeft: 10,
        paddingRight: 10,
    },
    descriptionContainer:{
        width: '100%',
        alignItems:'center',
        marginTop: 10,
        padding:5
    },
    descriptionHeaderText:{
        fontSize: 15,
        color:'#8E8E8E',
    },
    descriptionText:{
        marginTop: 5,
    },
  });

export default card;

Если я просто делаю анимацию статической и не запускаю функцию onLayout, анимация работает отлично. Но мне нужно получить эту высоту текстового поля, чтобы я знал, какой высоты мне нужно достичь, поскольку я извлекаю этот текст из базы данных. Либо когда я запускаю вызываемую функцию onLayout, getContentHeight(), она либо прыгает туда-сюда между 0 и maxHeight, либо просто остается на 0. Любая помощь приветствуется!


person frankied003    schedule 09.07.2020    source источник


Ответы (1)


useState является асинхронным. попробуй изменить это:

const getContentHeight = (event:any) => {
    setmaxContentHeight(event.nativeEvent.layout.height);
    if(maxContentHeight < 70){
        setdescriptionHeight(new Animated.Value(maxContentHeight));
    }
    else{
        setdescriptionHeight(new Animated.Value(70));
    }
}

к этому:

const getContentHeight = (event:any) => {
    const height = event.nativeEvent.layout.height;
    setmaxContentHeight(height);
    if(height < 70){
        setdescriptionHeight(new Animated.Value(height));
    }
    else{
        setdescriptionHeight(new Animated.Value(70));
    }
}

Кроме того, я думаю, что onLayout анимированных компонентов работает по-другому.

Попробуйте изменить onLayout следующим образом:

       <Animated.View
          onLayout={Animated.event([
            {
              nativeEvent: {
                layout: {
                  height: maxContentHeight
                }
              }
            }
          ])}
        />

а затем установить описание с помощью useEffect(() => {...}, [maxContentHeight])

person D10S    schedule 09.07.2020
comment
Спасибо за ваш ответ, это имеет смысл, но не повезло. Высота описания начинается с 0, это так странно. Я console.log(height) в функции getContentHeight(), и он не печатается... я неправильно вызываю функцию? Должен ли я просто сделать всю эту функцию асинхронной? - person frankied003; 09.07.2020
comment
Хорошо, теперь он просто говорит, что высота равна 10, что неверно... должно быть больше 100. - person frankied003; 09.07.2020
comment
По крайней мере, это срабатывает. Я думаю, что onLayout с анимированными компонентами работает по-другому. Я отредактировал свой ответ соответственно. Я буду рад узнать, работает ли это для моего самообразования. - person D10S; 09.07.2020