React Native가 있는 진행률 표시줄 애니메이션에 대한 이야기

웹 응용 프로그램과 이동(React Native)에서 애니메이션과 밀접하게 협력할 기회가 있습니다.때때로 나는 복잡한react원생 애니메이션에 헷갈려서 왜 사람들이react원생 부활 라이브러리를 만드는지 모르겠다.
본 강좌에서 저는 웹/모바일 애니메이션의 차이점과react원생 부활, 크로스플랫폼react 구성 요소의 장점을 설명하고 싶습니다.
브라우저에서 애니메이션 진도표를 만드는 방법을 보여 줍니다.
먼저 React 구성 요소를 만듭니다.
 const ProgressBar = ({ total, current, fill }) => {
   const percent = current / total;
   return (
     <div class="container">
       <div class="progress"></div>
     </div>
   )
 }
CSS 스타일:
.container {
  background-color: #eee;
  height: 4px;
  border-radius: 2px;
  margin: 20px;
  position: relative;
  overflow: hidden;
}

.progress {
  position: absolute;
  left: -100%;
  width: 100%;
  top: 0;
  bottom: 0;
  border-radius: 2px;
}
다음 단계는 도구의 스타일을 우리의 레이아웃에 적용하는 것이다.
...
  <div class="progress" style={{ transform: `translateX(${percent * 100}%)`, backgroundColor: fill }}></div>
...
결과를 살펴보겠습니다.

애니메이션은요?


웹 응용 프로그램에서 변환이나 배경색 등 속성을 위한 애니메이션을 설정하기 쉬우며 브라우저는 우리가 없는 상황에서 모든 애니메이션 작업을 완성할 것입니다.
우리의 스타일에 전환 속성을 추가하기만 하면 됩니다.
.progress {
  ...
  transition: all 0.2s;
}
이것은 결과입니다.

보기에 구성 요소는 매우 간단한데, 왜 내가 너희들에게 이 예를 보여 줄까?


React Native를 사용하여 이 구성 요소를 구현해 보겠습니다.
const AnimatedProgress = ({ fill, current, total }) => {
     const percent = current / total;

     return (
       <View style={styles.container}>
         <View style={[styles.progress, { backgroundColor: fill, transform: [{ translateX: `${percent * 100}%` }] }]} />
       </View>
     );
   };
읊다, 읊조리다
그렇다면 우리는 어떻게 원소의 폭을 얻을 수 있습니까?
useOnLayout 갈고리를 추가합니다.
export default function useOnLayout() {
  const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
  const onLayout = useCallback((event) => setLayout(event.nativeEvent.layout), []);

  return [layout, onLayout];
}
onLayout 프로세서를 패키지 뷰로 전송하려면 다음과 같이 하십시오.
const AnimatedProgress = ({ fill, current, total }) => {
     const percent = current / total;

    // we need only width property
     const [{ width }, onLayout] = useOnLayout();

     return (
       <View style={styles.container} onLayout={onLayout}>
         <View style={[styles.progress, { backgroundColor: fill, transform: [{ translateX: width * percent }] }]} />
       </View>
     );
   };
다음 단계는 translateX 속성을 설정하는 애니메이션입니다.
import { Animated } from "react-native";

// wrap our Animated.Value to useState for memoize it, alternatively you can use useRef
const [translateX] = useState(new Animated.Value(0));

useEffect(() => {
 Animated.timing(translateX, {
   toValue: width * percent,
   duration: 200,
   easing: Easing.inOut(Easing.ease),
   // using native driver for animation in UI thread 
   useNativeDriver: true
   }).start();
// call our animation when width or percent change
}, [width, percent]);

....

// Change View => Animated.View and translateX to our Animated.Value
<Animated.View style={[styles.progress, { backgroundColor: fill, transform: [{ translateX }] }]} />

오늘의 마지막 애니메이션 - 배경색 애니메이션.


그것은 웹 응용 프로그램처럼 간단합니까?
컬러 애니메이션을 작성하기 전에, 우리는reactnativereanimated library로 전환합니다. 이것은 더욱 유연하고 더 많은 정의 기능을 가지고 있습니다.
reactnativereanimated는 뒤로 기능하는 API를 가지고 있기 때문에 코드 라이브러리를 다시 쓸 필요가 없습니다.
  • 주의: 설정에서use Native Driver:true 속성을 삭제했습니다. 왜냐하면react native reanimated는 이미 본 기기의 UI 라인에서 모든 애니메이션을 실행했기 때문입니다.
  • import Animated, { Easing } from "react-native-reanimated";
    
    useEffect(() => {
        Animated.timing(translateX, {
          toValue: width * percent,
          duration: 200,
          easing: Easing.inOut(Easing.ease)
        }).start();
      }, [width, percent]);
    
    reactnative에서 색 애니메이션을 설정하는 주요 문제는 브라우저와 같은 전환이 부족하다는 것입니다.솔직히 브라우저는 백그라운드에서 CSS, 삽입 색상 등이 있는 모든 애니메이션을 많이 했습니다.
    그래서 우리는 스스로 색을 위해 과도를 만들어야 한다.이전에reactnativereanimated 라이브러리로 전환했습니다. 유용한 기능이 많습니다. 이 기능을 사용할 것입니다.
    색상 보간 프로세스를 상상해 보십시오.
    1) Convert color: Firstly let's convert color to one format - for example, RGBA(you can choose a different one - HSV, HSL)
    2) we need steam of animation which we can iterate - it can be usual for us *Animated.Value*, which we can animate from 0 to some value.
    3) In this time we will make interpolation of animation this value each of color part (r, g, b, a);
    4) combine all these values into one color.
    
    중요한 요구 사항은 애니메이션이 네이티브 UI 스레드에서 작동해야 한다는 것입니다.이것이 바로 우리가 react native에서string 색깔까지의 간단한 삽입값을 사용할 수 없는 이유입니다. 예를 들어 다음과 같습니다.
     const interpolateColor = animatedValue.interpolate({
       inputRange: [0, 150],
       outputRange: ['rgb(0,0,0)', 'rgb(51, 250, 170)']
     })
    
    원본 UI 스레드 애니메이션은 매우 큰 한계가 있습니다. 비레이아웃 속성에 대해서만 애니메이션을 설정할 수 있습니다. 예를 들어 변환과 불투명도는 작동할 수 있지만 Flexbox와 위치 속성은 할 수 없습니다.
    이것은 우리가 시작하기 전에 애니메이션을 정의해야 하기 때문이다.
    애니메이션에 대한 자세한 내용은 다음을 참조하십시오. https://reactnative.dev/blog/2017/02/14/using-native-driver-for-animated
    우리는 도구 충전이 변할 때 애니메이션을 실행하기를 원하기 때문에, 플러그인을 실행하기 위해 이전의 충전 값을 저장해야 한다.
    색상 보간 값에 대한 사용자 정의 연결을 만들고 이전 값을 저장합니다.
    export default function useAnimatedColor(color) {  
      // store our previous color in ref
      const prevColor = useRef(color);
    
      // TODO write color interpolation
    
      // updating previous value after creating interpolation
      prevColor.current = color;
    
      // TODO return color interpolation
      return color;
    }
    
    다음 단계는 색 값을 추가하는 것입니다. 색을 삽입하고 색이 변할 때 애니메이션을 실행합니다.물론, 우리는reactnative의useEffect를 사용할 수 있지만,reactnativereanimated는 자체의useCode 연결이 있습니다.
    // define input range for interpolation
    const inputRange = [0, 50];
    
    export default function useAnimatedColor(color) {
      // store our value to ref for memoization
      const colorValue = useRef(new Animated.Value(0));
      ...
      useCode(() => {
          const [from, to] = inputRange;
          // TODO iterate colorValue in range
        }, [color]);
    }
    
    reactnativereanimated는 모든 프레임의 시계를 제어하는 메커니즘을 가지고 있습니다.그리고 유니버설 함수 runTiming-는 시간 애니메이션에 사용됩니다. 이 강좌의 문서나 전체 코드에서 원본 코드를 찾을 수 있습니다.
    https://github.com/serzmerz/react-native-progress-bar
    import Animated, { Clock } from "react-native-reanimated";
    
    const { set, useCode } = Animated;
    
    export default function useAnimatedColor(color) {
      const colorValue = useRef(new Animated.Value(0));
      ...
      // create clock instance and memoize it
      const clock = useRef(new Clock());
    
        useCode(() => {
          const [from, to] = inputRange;
          return [set(colorValue.current, runTiming(clock.current, from, to))];
        }, [color]);
    }
    
    우리가 이 갈고리에서 한 마지막 일 - 색깔 삽입값, 이 갈고리의 전체 코드는 다음과 같다.
    const inputRange = [0, 50];
    
    export default function useAnimatedColor(color) {
      const colorValue = useRef(new Animated.Value(0));
      const prevColor = useRef(color);
    
      // call our interpolateColors and wrap it to useMemo
      const backgroundColor = useMemo(
        () =>
          interpolateColors(colorValue.current, {
            inputRange,
            outputColorRange: [prevColor.current, color]
          }),
        [color]
      );
    
      prevColor.current = color;
    
      const clock = useRef(new Clock());
    
      useCode(() => {
        const [from, to] = inputRange;
        return [set(colorValue.current, runTiming(clock.current, from, to))];
      }, [color]);
    
      return backgroundColor;
    }
    
    플러그인 색상 함수는요?현재reactnativereanimated는 코드 라이브러리에서 실행되었지만 아직 발표되지 않았습니다.이 강좌를 읽고reactnativereanimated의 버전이 1.9.0보다 높으면, 이 함수는 그 안에 있어야 합니다.
    참고로 우리는 이 함수의 작업 원리를 깊이 이해한다.
    import { processColor } from "react-native";
    import Animated, { round, color, interpolate, Extrapolate } from "react-native-reanimated";
    
    // functions for getting each part of our color
    function red(c) {
      return (c >> 16) & 255;
    }
    function green(c) {
      return (c >> 8) & 255;
    }
    function blue(c) {
      return c & 255;
    }
    function opacity(c) {
      return ((c >> 24) & 255) / 255;
    }
    
    /**
     * Use this if you want to interpolate an `Animated.Value` into color values.
     *
     * #### Why is this needed?
     *
     * Unfortunately, if you'll pass color values directly into the `outputRange` option
     * of `interpolate()` function, that won't really work (at least at the moment).
     * See https://github.com/software-mansion/react-native-reanimated/issues/181 .
     *
     * So, for now you can just use this helper instead.
     */
    export default function interpolateColors(animationValue, options) {
      const { inputRange, outputColorRange } = options;
      // convert our colors to rgba format 
      const colors = outputColorRange.map(processColor);
    
      // interpolate each part of our color
      const r = round(
        interpolate(animationValue, {
          inputRange,
          // map only necessary part 
          outputRange: colors.map(red),
          extrapolate: Extrapolate.CLAMP
        })
      );
      const g = round(
        interpolate(animationValue, {
          inputRange,
          outputRange: colors.map(green),
          extrapolate: Extrapolate.CLAMP
        })
      );
      const b = round(
        interpolate(animationValue, {
          inputRange,
          outputRange: colors.map(blue),
          extrapolate: Extrapolate.CLAMP
        })
      );
      const a = interpolate(animationValue, {
        inputRange,
        outputRange: colors.map(opacity),
        extrapolate: Extrapolate.CLAMP
      });
    
      // combine all parts to one color interpolation
      return color(r, g, b, a);
    }
    
    
    이렇게 하면 Animated Progress 구성 요소에서 우리의 갈고리를 호출할 수 있습니다.
    const AnimatedProgress = ({ fill, current, total }) => {
      const backgroundColor = useAnimatedColor(fill);
    
      ...
      // pass animated props to view
      <Animated.View style={[styles.progress, { backgroundColor, transform: [{ translateX }] }]} />
      ...
    }
    

    너는 인터넷과 휴대전화의 배치가 같다는 것을 알아차렸니?


    오늘의 마지막 일은 크로스플랫폼 제작 진도표 구성 요소입니다.
    이 목표를 실현하기 위해서는 두 가지 절차를 취해야 한다.
    1) 우리의 연결고리를 두 개의 연결고리로 나눈다.
    - 애니메이션 색상을 사용합니다.js/useAnimatedColor.출생지의회사 명
    - 애니메이션 진행 상태를 사용합니다.js/useAnimatedProgress.출생지의회사 명
    .출생지의js 확장은 metrobundler가 모바일 플랫폼에 불러옵니다.
    .js 확장은 웹에 불러옵니다.
    웹에 대해 우리는 단지 이러한 연결을 간소화하기만 하면 된다.모든 애니메이션은transition 속성으로 완성됩니다.
    애니메이션 색상을 사용합니다.js:
    export default function useAnimatedColor(color) {
     return color;
    }
    
    애니메이션을 사용하여 진행합니다.회사 명
    export default function useAnimatedProgress(width, percent) {
      return width * percent;
    }
    
    2) 스타일에서 웹 응용 프로그램에 변환을 추가합니다.
    export default StyleSheet.create({
      ...
      progress: {
        ...
        // select only web for avoiding error on mobile devices
        ...Platform.select({ web: { transition: "0.3s all ease-in-out" } })
      }
    });
    
    와!우리는 이미 모든 플랫폼을 위해 로컬 애니메이션이 있는 크로스플랫폼 구성 요소를 구축했다.
    github에서 모든 소스 코드를 찾을 수 있습니다: https://github.com/serzmerz/react-native-progress-bar
    사용 예: https://github.com/serzmerz/TestReactNativeProgressBar
    당신의 목적을 위해 완성된 라이브러리를 설치합니다.
    yarn add react-native-reanimated-progress-bar
    

    좋은 웹페이지 즐겨찾기