question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AnimateHeight component?

See original GitHub issue

I was looking to find examples can came across the demos of the <AnimateHeight /> component, but can’t find it anywhere. Are there still plans to release it into moti anytime?

https://twitter.com/FernandoTheRojo/status/1372695982056558597

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
nandorojocommented, Aug 28, 2021

Here’s my current code I’m using in the beatgig.com app.

Consider it as-is code 😎

import React, { useState, useEffect, useRef } from 'react'
import { View as MotiView, TransitionConfig, useDynamicAnimation } from 'moti'
import { StyleSheet, Platform } from 'react-native'

type Props = {
  children?: React.ReactNode
  /**
   * If `true`, the height will automatically animate to 0. Default: `false`.
   */
  hide?: boolean
  /**
   * Custom transition for the outer `moti` View, which animates the `height`.
   *
   * See the [moti docs](https://moti.fyi/animations#customize-your-animation) for more info.
   *
   * Defaults to a `type: 'timing'` animation with a `delay` of 200. You can use this to customize that.
   */
  containerTransition?: TransitionConfig
  onHeightDidAnimate?: (height: number) => void
  /**
   * Defines where the expanded view will be anchored.
   *
   * Default: `top`
   *
   * This prop is untested, use with caution
   */
  enterFrom?: 'bottom' | 'top'
  initialHeight?: number
} & React.ComponentProps<typeof MotiView>

function AnimateHeight({
  children,
  hide = false,
  style,
  animate = {},
  delay = Platform.select({ web: 250, default: 0 }),
  containerTransition = { type: 'timing', delay },
  transition = {
    type: 'timing',
    delay,
  },
  enterFrom = 'top',
  onHeightDidAnimate,
  initialHeight = 0,
  ...motiViewProps
}: Props) {
  const animation = useDynamicAnimation(() => ({
    height: hide ? 0 : initialHeight,
  }))
  const [measuredHeight, setHeight] = useState(initialHeight)

  let height = measuredHeight

  if (hide) {
    height = 0
  }

  const mounted = useRef(false)

  useEffect(function mount() {
    mounted.current = true

    return () => {
      mounted.current = false
    }
  }, [])

  useEffect(
    function updateHeight() {
      if (hide) {
        animation.animateTo({
          height: 0,
        })
      } else if (animation.current?.height !== height) {
        animation.animateTo({
          height,
        })
      }
    },
    [animation, height, hide]
  )

  const notVisible = !height || hide

  return (
    <MotiView
      state={animation}
      transition={containerTransition}
      onDidAnimate={
        onHeightDidAnimate &&
        ((key) => key === 'height' && onHeightDidAnimate?.(height))
      }
      // TODO shouldn't this always be hidden...?
      style={[style, height || hide ? styles.hidden : styles.visible]}
    >
      <MotiView
        {...motiViewProps}
        style={
          // notVisible &&
          [
            StyleSheet.absoluteFillObject,
            enterFrom === 'top' ? styles.autoBottom : styles.autoTop,
          ]
        }
        animate={{ ...animate, opacity: notVisible ? 0 : 1 }}
        transition={transition}
        onLayout={(next) => {
          if (mounted.current) {
            setHeight(next.nativeEvent.layout.height)
          }
        }}
      >
        {children}
      </MotiView>
    </MotiView>
  )
}

const styles = StyleSheet.create({
  autoBottom: {
    bottom: 'auto',
  },
  autoTop: {
    top: 'auto',
  },
  hidden: {
    overflow: 'hidden',
  },
  visible: {
    overflow: 'visible',
  },
})

export default AnimateHeight
0reactions
breynolds-devcommented, Aug 30, 2021

So I played around and made the suggested changes, however I won’t guarantee anything. It’s my first time really working directly with the Reanimated API and using useAnimatedReaction so if I’ve made a big screw up let me know!

One big change I made was only animating to the max window height if the height would be bigger - I’m sure there is better use cases but for a couple of large lists of items I was working with that made a nice improvement in animation performance. There was no reason to animate things off screen so I figured it would help. It’s really easy to remove if it’s not something you find useful

import { View as MotiView, TransitionConfig, useDynamicAnimation } from "moti";
import React from "react";
import { StyleSheet, Platform, Dimensions } from "react-native";
import { useAnimatedReaction, useSharedValue } from "react-native-reanimated";


const windowHeight = Dimensions.get( "window" ).height;

type Props = {
  children?: React.ReactNode
  /**
   * Custom transition for the outer `moti` View, which animates the `height`.
   *
   * See the [moti docs](https://moti.fyi/animations#customize-your-animation) for more info.
   *
   * Defaults to a `type: 'timing'` animation with a `delay` of 200. You can use this to customize that.
   */
  containerTransition?: TransitionConfig
  /**
   * If `true`, the height will automatically animate to 0. Default: `false`.
   */
  hide?: boolean
  initialHeight?: number
  onHeightDidAnimate?: ( height: number ) => void
} & React.ComponentProps<typeof MotiView>;

const styles = StyleSheet.create( {
  autoBottom: {
    bottom: "auto",
  },
  hidden: {
    overflow: "hidden",
  },
} );

const DELAY = Platform.select( { web: 250, default: 0 } );
const defaultTransition: TransitionConfig = {
  type: "timing",
  delay: DELAY,
};

const AnimateHeight: React.FC<Props> = ( {
  animate = {},
  children,
  containerTransition = defaultTransition,
  hide = false,
  initialHeight = 0,
  onHeightDidAnimate,
  style,
  transition = defaultTransition,
  ...motiViewProps
} ) => {
  const measuredHeight = useSharedValue( initialHeight );
  const animation = useDynamicAnimation( () => ( { height: hide ? 0 : measuredHeight.value } ) );
  const height = hide ? 0 : measuredHeight.value;
  const isVisible = height || !hide;

  useAnimatedReaction(
    () => hide ? 0 : measuredHeight.value,
    ( result ) => {
      if ( result > windowHeight ) {
        animation.animateTo( {
          height: windowHeight,
        } );
      }

      animation.animateTo( {
        height: result,
      } );
    },
    [ animation, height, hide ],
  );

  return (
    <MotiView
      onDidAnimate={ onHeightDidAnimate && ( ( key ) => key === "height" && onHeightDidAnimate( height ) ) }
      state={animation}
      style={[ style, styles.hidden ]}
      transition={containerTransition}
    >
      <MotiView
        {...motiViewProps}
        style={ [ StyleSheet.absoluteFillObject, styles.autoBottom ] }
        animate={{ ...animate, opacity: isVisible ? 1 : 0 }}
        transition={transition}
        onLayout={( next ) => {
          measuredHeight.value = next.nativeEvent.layout.height;
        } }
      >
        {children}
      </MotiView>
    </MotiView>
  );
};

export default AnimateHeight;

Read more comments on GitHub >

github_iconTop Results From Across the Web

react-animate-height - npm
Lightweight React component for animating height using CSS transitions. ... Start using react-animate-height in your project by running `npm ...
Read more >
React Animate Height
Lightweight React component for animating height using CSS transitions. Slide up/down the element, and to any specific height. Check the demo below. CSS...
Read more >
How to animate element height in React with ... - Stack Overflow
<AnimateHeight duration={ 500 } height={ 'auto' } > <h1>Your content goes here</h1> <p>Put as many React or HTML components here.
Read more >
Animating height — the right way - Medium
Documentation can be found here. The most important components in this library is AnimateHeight and AnimateHeightContainer. Let's examine them:
Read more >
react-animate-height examples - CodeSandbox
Learn how to use react-animate-height by viewing and forking example apps that make use of react-animate-height on CodeSandbox.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found