Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Progress Bar in React Native

Progress Bar

~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Progress bars also have no built-in, cross-platform component in current React Native (the former ProgressBarAndroid/ProgressViewIOS were removed) – the common solution: a View with an animated percentage width.

1. Description

A progress bar consists of two nested Views: an outer one with a fixed width (the "track") and an inner one whose width (as a percentage, or as an animated Animated.Value) represents the current progress.

2. Short example

<View style={{ height: 8, backgroundColor: '#e5e7eb', borderRadius: 4 }}>
  <View style={{ width: `${progress}%`, height: '100%', backgroundColor: '#2563eb', borderRadius: 4 }} />
</View>

3. Complete project: a file upload simulation

npx create-expo-app progress-bar-demo
cd progress-bar-demo
components/ProgressBar.js
import { useEffect, useRef } from 'react';
import { Animated, View, StyleSheet } from 'react-native';

function ProgressBar({ percent }) {
  const width = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(width, {
      toValue: percent,
      duration: 300,
      useNativeDriver: false, // width can't be animated with the native driver
    }).start();
  }, [percent]);

  return (
    <View style={styles.track}>
      <Animated.View
        style={[
          styles.fill,
          { width: width.interpolate({ inputRange: [0, 100], outputRange: ['0%', '100%'] }) },
        ]}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  track: { height: 10, backgroundColor: '#e5e7eb', borderRadius: 5, overflow: 'hidden' },
  fill: { height: '100%', backgroundColor: '#2563eb', borderRadius: 5 },
});

export default ProgressBar;
App.js
import { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import ProgressBar from './components/ProgressBar';

export default function App() {
  const [percent, setPercent] = useState(0);

  function simulateUpload() {
    setPercent(0);
    const interval = setInterval(() => {
      setPercent((current) => {
        const next = current + 10;
        if (next >= 100) clearInterval(interval);
        return Math.min(next, 100);
      });
    }, 200);
  }

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Upload: {percent}%</Text>
      <ProgressBar percent={percent} />
      <View style={styles.button}>
        <Button title="Start upload" onPress={simulateUpload} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, paddingTop: 80, paddingHorizontal: 24 },
  label: { marginBottom: 8, fontSize: 16 },
  button: { marginTop: 20 },
});

4. Explanation

  • useNativeDriver: false is MANDATORY here – width is a layout property, and the native driver only supports opacity/transform.
  • width.interpolate() translates the numeric animated value (0–100) into a percentage STRING ('0%''100%'), since width in style expects either a number (pixels) or a percentage string.
  • overflow: 'hidden' on the "track" clips the inner fill at the rounded corners instead of squarely overhanging the edge.
  • setInterval simulates a real network upload progress here; in a real app the percentage would typically come from the onUploadProgress callback of an HTTP library like Axios (see the "Axios" chapter).

5. Outputs

Ausgabe
Text "Upload: 0%" above an empty gray bar, below it a "Start upload" button. After tapping, the bar fills by 10% every 200ms (blue, animated, rounded) up to 100%, with the percentage text counting up in sync.