【问题标题】:React native animation progress barReact 原生动画进度条
【发布时间】:2021-06-22 09:09:00
【问题描述】:

我正在尝试为我的 react-native 项目构建一个进度条 它应该是在许多地方使用的通用组件。 请看我的代码:

进度条 tsx:

import React, { useEffect } from 'react'
import { Animated, StyleProp, StyleSheet, View, ViewStyle } from 'react-native'

interface Props {
  total: number
  progress: number
  color?: string
  backgroundColor?: string
  height?: number
  style?: StyleProp<ViewStyle>
  animDelay?: number
  animDuration?: number
  testID?: string
}

const ProgressBar = ({
  color,
  backgroundColor,
  style,
  height,
  animDelay,
  animDuration,
  total,
  progress,
  testID = 'progress-bar',
}: Props): JSX.Element => {
  const minWidthValue = 5.4
  const percentage = total && progress ? Math.min(progress, total) / total : 0
  const minDisplayWidth =
    percentage > 0 && percentage < minWidthValue ? minWidthValue : percentage
  const barWidth = `${Math.max(minDisplayWidth, Math.floor(percentage * 100))}%`

  useEffect(() => {
    const animationValue = new Animated.Value(0)
    Animated.timing(animationValue, {
      toValue: progress,
      delay: animDelay,
      duration: animDuration,
      useNativeDriver: true,
    }).start();
  }, []);

  return (
    <View
      testID={testID}
      style={[
        styles.container,
        height ? { height } : undefined,
        backgroundColor ? { backgroundColor } : undefined,
        style,
      ]}>
      <Animated.View
        style={[
          styles.bar,
          {
            backgroundColor: color,
            width: barWidth,
          },
        ]}
      />
    </View>
  )
}

export default ProgressBar

const BORDER_RADIUS = 15

const styles = StyleSheet.create({
  bar: {
    borderRadius: BORDER_RADIUS,
    height: '100%',
  },
  container: {
    borderRadius: BORDER_RADIUS,
    flexDirection: 'row',
    height: 30,
    overflow: 'hidden',
    width: '100%',
  },
})

还有usesage的例子,比如home.tsx:

<ProgressBarWrapper total={100} progress={50} testID='test-id-test-1' />

所以会发生什么,总长度(100%),我希望当这个组件加载时动画从 0 移动到 50 开始时的条形

使用上面的代码,我只得到一个静态栏,根本不动.. 有人可以指出我做错了什么吗? 示例代码将非常有帮助 干杯

编辑:

我已经更新了代码

useNativeDriver

并在此处使用interpolation 以避免使用“clamp”产生振荡

但是,动画仍然没有移动/工作,想知道对此有何建议。 谢谢

const ProgressBarInternal = ({
  color,
  backgroundColor,
  style,
  height,
  animDelay,
  animDuration,
  total,
  progress,
  testID = 'progress-bar',
  borderRadius,
  containerHeight,
  onAnimationDidEnd,
}: Props): JSX.Element => {
  const minWidthValue = 5.4
  const percentage = total && progress ? Math.min(progress, total) / total : 0
  const minDisplayWidth =
    percentage > 0 && percentage < minWidthValue ? minWidthValue : percentage
  const progressingBarWidthPercentage = `${Math.max(minDisplayWidth, Math.floor(percentage * 100))}%`

  const animatingProgressBar = useRef(new Animated.Value(0))
  useEffect(() => {
    Animated.timing(animatingProgressBar.current, {
      toValue: 0,
      delay: animDelay,
      duration: animDuration,
      useNativeDriver: true,
    }).start()
  }, []
  );

  return (
    <View
      testID={testID}
      style={...}>
      <Animated.View        
        style={[
          styles.bar,
          { borderRadius: borderRadius },
          {
            backgroundColor: color,
            width: progressingBarWidthPercentage,
          },
          {
            transform: [
              {
                translateX: animatingProgressBar.current.interpolate({
                  inputRange: [1, 100],
                  outputRange: ["0%", "100%"],
                  extrapolate: "clamp"
                }),
              },
            ],
          },
        ]}
      />
    </View>
  )
}

【问题讨论】:

    标签: javascript reactjs typescript react-native animation


    【解决方案1】:

    当 useNativeDriver 设置为 true 时,我遇到了类似的行为。

    将 useNativeDriver 更改为 false 可能会解决您的问题

    这也是我如何实现动画宽度的示例:

    const barWidth = useRef(new Animated.Value(0)).current;
    const progressPercent = barWidth.interpolate({
        inputRange: [0, 100],
        outputRange: ["0%", `100%`],
    });
    useEffect(() => {
        animatedController.setValue(0)
    
        Animated.timing(barWidth, {
            duration: 5000,
            toValue: 100,
            useNativeDriver: false
        }).start();
    }, [])
    
    return (
    <View style={...}>
      <Animated.View
        style={[
          styles.bar,
          {
            backgroundColor: color,
            width: progressPercent,
          }
       ]}
      />
    </View>
    

    )

    【讨论】:

      【解决方案2】:

      您不能使用 width 属性设置动画。

      使用transform instead

      一个包含代码基础的示例。

      import React, { useEffect, useRef } from 'react'
      import { Animated, StyleProp, StyleSheet, View, ViewStyle } from 'react-native'
      
      interface Props {
        total: number
        progress: number
        color?: string
        backgroundColor?: string
        height?: number
        style?: StyleProp<ViewStyle>
        animDelay?: number
        animDuration?: number
        testID?: string
      }
      
      const Test = ({
        color,
        backgroundColor,
        style,
        height,
        animDelay,
        animDuration,
        total,
        progress,
        testID = 'progress-bar',
      }: Props): JSX.Element => {
        //const minWidthValue = 5.4
        //const percentage = total && progress ? Math.min(progress, total) / total : 0
        //const minDisplayWidth =
        //  percentage > 0 && percentage < minWidthValue ? minWidthValue : percentage
          //const barWidth = `${Math.max(minDisplayWidth, Math.floor(percentage * 100))}%`
          const barWidth = useRef(new Animated.Value(1)).current;
      
        useEffect(() => {
          //const animationValue = new Animated.Value(0)
          Animated.timing(barWidth, {
            toValue: 9,//progress,
            //delay: 1000,//animDelay,
            duration: 9000,//animDuration,
            useNativeDriver: true,
          }).start();
        }, []
        );
      
        return (
          <View
            testID={testID}
            style={[
              styles.container,
              height ? { height } : undefined,
              backgroundColor ? { backgroundColor } : undefined,
              style,
            ]}>
            <Animated.View
              style={[
                styles.bar,
                {
                  backgroundColor: color,
                  width: 50,
                },
                {transform: [{ scaleX: barWidth }]}
              ]}
            />
          </View>
        )
      }
      
      export default Test
      
      const BORDER_RADIUS = 5
      
      const styles = StyleSheet.create({
        bar: {
          borderRadius: BORDER_RADIUS,
          height: '100%',
        },
        container: {
          borderRadius: BORDER_RADIUS,
          flexDirection: 'row',
          height: 30,
          overflow: 'hidden',
          width: '100%',
        },
      })

      【讨论】:

      • 嗨,documurloc,感谢您的建议,请查看我的更新代码,我正在尝试使用“useNativeDriver”和“插值”,不知何故,动画没有发生,你能帮我指出什么吗我的代码有问题吗?欢呼
      猜你喜欢
      • 1970-01-01
      • 2014-04-23
      • 1970-01-01
      • 1970-01-01
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      相关资源
      最近更新 更多