Home > Mobile >  React native animation progress bar with image
React native animation progress bar with image

Time:06-27

Today i want to make a progress bar with a image on the left. Unfortunately I can't position the image in the right place. For now it looks like that enter image description here

I want to looks something like that - enter image description here

My code so far -

<View
  style={{
    flexDirection: "row",
    alignSelf: "center",
    marginBottom: "20%",
    marginTop: "10%",
  }}
>
  <View
    style={{
      width: "90%",
      height: 30,
      padding: 2.5,
      backgroundColor: "#00000020",
      borderRadius: 30,
    }}
  >
    {/* <Animated.View
      style={[
        {
          width: "100%",
          height: 25,
          borderRadius: 15,
          backgroundColor: "#f5de41",
        },
        {
          width: progressAnim,
        },
      ]}
    ></Animated.View> */}
    <Image
      source={require("./assets/lion.png")}
      style={{
        height: 44,
        height: 44,
        position: "absolute",
      }}
      resizeMode="contain"
    />
  </View>
</View>

I tried to add left: '-62%' in style of iamge but it not works. I am not sure how to move the lion to the left?

CodePudding user response:

One approach would be to remove the absolute position and use flexbox to align the the image to end of the row:

const ProgressBar = ({imgSource,imgStyle,imgSize,style,progress,color})=>{
  let loadingAnim = useRef(new Animated.Value(progress)).current;
  const [{width,height},setViewDimensions] = useState({});
  // get parent view size
  const onLayout=({nativeEvent})=>{
    setViewDimensions({
      width:nativeEvent.layout.width,
      height:nativeEvent.layout.height
    })
  }
  const animatedWidth =loadingAnim.interpolate({
    inputRange:[0,1],
    outputRange:[0,width-imgSize],
    extrapolate:'clamp'
  })
  const containerAnimation = {
    margin:0,
    padding:0,
    width:Animated.add(animatedWidth,imgSize),
    backgroundColor:color,
    height:'100%',
    justifyContent:'center',
    overflow:'hidden'
  }
  useEffect(()=>{
    Animated.timing(loadingAnim,{
      toValue:progress,
      duration:100
    }).start()
  },[progress])
  return(
    <View style={[styles.loadingContainer,{height:imgSize*1.5||null},style]} onLayout={onLayout}>
      <Animated.View style={[styles.loadingContainer,containerAnimation]}>
        <Animated.Image
          source={imgSource}
          style={[{height:imgSize,width:imgSize,alignSelf:'flex-end'},imgStyle,{}]}
        />
      </Animated.View>
    </View> 
  )
}

I found this approach to be slightly un-smooth. I think this is because the width of image's parent view was being animated, and not the actual position of the image.

Another approach would be to animate the image:

const ProgressBar = ({imgSource,imgStyle,imgSize,style,progress,color})=>{
  let widthAnim = useRef(new Animated.Value(progress)).current;
  const [{width,height},setViewDimensions] = useState({});
  // get parent view width to determine progress view size
  const onLayout=({nativeEvent})=>{
    setViewDimensions({
      width:nativeEvent.layout.width,
      height:nativeEvent.layout.height
    })
  }
  const animatedWidth = widthAnim.interpolate({
      inputRange:[0,1],
      outputRange:[0,width-imgSize],
      extrapolate:'clamp'
    })
  const containerAnimation = {
    // min width will be imgSize
    width:Animated.add(animatedWidth,imgSize),
    backgroundColor:color,  
  }
  const imgAnimation = {
    left:animatedWidth
  }
  // animate progress changess
  useEffect(()=>{
    Animated.timing(widthAnim,{
      toValue:progress,
      duration:100
    }).start()
  },[progress])
  return(
    <View>
      <View style={[styles.loadingContainer,{height:imgSize*1.25||null},style]} onLayout={onLayout}>
        <Animated.View style={[styles.progressBar,containerAnimation]}/>
      </View> 
          <Animated.Image
            source={imgSource}
            style={[styles.image,{height:imgSize,width:imgSize},imgStyle,imgAnimation]}
            resizeMode='contain'
          />
    </View> 
  )
}
  • Related