DEV Community

Nguyễn Hữu Hiếu
Nguyễn Hữu Hiếu

Posted on

react-native: show more, expandable animation

Problem

  • Need to show more, expandable, calculate view before see it on view

Solution

  • Step 1: calculate item before animate it

    • set position to absolute.
    • set opacity to 0.
    • set measured=1 and cache it
  • Step 2: use react-native-animatable to animate item

import * as Animatable from 'react-native-animatable';
import React, {useState} from 'react';
import {Pressable, Text, TextStyle, View, ViewStyle} from 'react-native';

export const ShowMoreDemo = () => {
  return (
    <View>
      <Text>Parent Content 1</Text>
      <ShowMore>
        <Text>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam rem
          ducimus sit ipsa eligendi, beatae tempora ullam obcaecati at ab
          consectetur ea eveniet labore non quod fugiat itaque facilis fuga?
        </Text>
      </ShowMore>
      <Text>Parent Content 2</Text>
    </View>
  );
};

const ShowMore: React.FC = ({children}) => {
  // const minHeight = 300;
  const [isShowMore, setIsShowMore] = useState(false);
  const [measured, setMeasured] = useState(false);
  const [contentHeight, setContentHeight] = useState(0);

  const [contentStyle, setContentStyle] = useState<ViewStyle>({
    opacity: 0,
    position: 'absolute',
  });

  console.log('measured', measured, contentHeight);

  return (
    <>
      <View
        style={contentStyle}
        onLayout={e => {
          if (!measured) {
            setContentHeight(e.nativeEvent.layout.height);
            setMeasured(true);
          }
        }}>
        {!measured ? (
          children
        ) : (
          <Animatable.View
            style={
              {
                backgroundColor: 'red',
                height: isShowMore ? contentHeight : 0,
                opacity: isShowMore ? 1 : 0,
              } as ViewStyle
            }
            duration={300}
            transition={['height', 'opacity']}>
            {children}
          </Animatable.View>
        )}
      </View>
      <Pressable
        style={
          {
            height: 48,
            justifyContent: 'center',
            alignItems: 'center',
          } as ViewStyle
        }
        onPress={() => {
          setIsShowMore(!isShowMore);
          setContentStyle({
            opacity: 1,
            position: 'relative',
          });
        }}>
        <Text
          style={
            {
              color: '#000',
              fontSize: 12,
              fontWeight: 'bold',
            } as TextStyle
          }>
          {isShowMore ? 'Show Less' : 'Show More'}
        </Text>
      </Pressable>
    </>
  );
};

Enter fullscreen mode Exit fullscreen mode

Top comments (0)