代码之家  ›  专栏  ›  技术社区  ›  sefirosu

反应本机动画进度栏

  •  0
  • sefirosu  · 技术社区  · 5 年前

    我正在尝试为我的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的例子,比如说在家里。tsx:

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

    enter image description here

    有了上面的代码,我只得到一个静态条,根本没有移动。。 有人能指出我哪里做错了吗? 干杯

    已编辑:

    我已更新代码

    useNativeDriver
    

    interpolation 此处使用“钳位”避免振荡

    然而,动画仍然没有移动/工作,不知道有什么建议。 谢谢

    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>
      )
    }
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Getsumi3    5 年前

    将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
  •  0
  •   docmurloc    5 年前

    不能使用“宽度”属性设置动画。

    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%',
      },
    })
    推荐文章