How do I overlay ActivityIndicator in react-native?

JavascriptReact Native

Javascript Problem Overview


I have a View with few form elements and a button (TouchableHighlight). On clicking the button, an Activity Indicator should be shown as an overlay to the existing view. The Activity Indicator should be centered within the page and the existing view should be slightly blurred to indicate overlay. I tried different options but could not get it to work.

render() {
    const { username, password } = this.state;

    return (
        <View style={styles.container}>
            <View style={styles.group}>
                <Text style={styles.text}>Username:</Text>
                <TextInput
                    style={styles.input}
                    onChangeText={this.handleUserNameChange.bind(this)}
                    value={username}
                    underlineColorAndroid="transparent"
                />
            </View>
            <View style={styles.group}>
                <Text style={styles.text}>Password:</Text>
                <TextInput
                    style={styles.input}
                    secureTextEntry={true}
                    onChangeText={this.handlePasswordChange.bind(this)}
                    value={password}
                    underlineColorAndroid="transparent"
                />
            </View>
            <TouchableHighlight
                style={styles.button}
                onPress={this.handleLogin.bind(this)}>
                <Text style={styles.buttonText}>Logon</Text>
            </TouchableHighlight>
        </View>
    );
}

Existing styles:

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'flex-start',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
        marginTop: 60
    },
    group: {
        alignItems: 'flex-start',
        padding: 10
    },
    input: {
        width: 150,
        padding: 2,
        paddingLeft: 5,
        borderColor: 'gray',
        borderWidth: 1
    },
    text: {
        padding: 0
    },
    button: {
        width: 150,
        backgroundColor: '#2299F2',
        padding: 15,
        marginTop: 20,
        borderRadius: 5
    },
    buttonText: {
        textAlign: 'center',
        color: '#fff',
        fontSize: 24
    },
});

I need to an ActivityIndicator to the above View, overlay the view, and center the ActivityIndicator.

Javascript Solutions


Solution 1 - Javascript

For this to work, you'd need to absolute position it, and render it after the elements that should be underneath the overlay:

  loading: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center'
  }

Then simply compose it into the render method conditionally, based on a loading state. I am going to assume this.handleLogin sets some sort of loading state already.

Make sure it's rendered last so it takes precedence.

...
{this.state.loading &&
    <View style={styles.loading}>
      <ActivityIndicator size='large' />
    </View>
}

Solution 2 - Javascript

Here is a complete example using create react native app.

import React from 'react';
import {StyleSheet, ActivityIndicator, View} from "react-native";

export default class Example extends React.Component {

    constructor(props) {
        super(props);

        this.state = {}

    render() {
        return (
            <View
                style={{flex: 1}}
            >
                  //Add other content here
                  {this.state.loading &&
                  <View style={styles.loading}>
                      <ActivityIndicator/>
                  </View>
                  }
                </View>
            );
        }
    }

    showLoading() {
       this.setState({loading: true})
    }

    hideLoading() {
       this.setState({loading: false})
    }

    const styles = StyleSheet.create({
        loading: {
            position: 'absolute',
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
            opacity: 0.5,
            backgroundColor: 'black',
            justifyContent: 'center',
            alignItems: 'center'
        }
    })

Solution 3 - Javascript

You can build a nice overlay using the activity indicator component by also leveraging the modal capabilities like Sanaur suggests.

For example you can use the below functional component. You can control it's visibility through the show prop that you can tie to a state in your screen.

An example that you can adapt to your needs.

const ModalActivityIndicator = props => {
  const {
    show = false,
    color = "black",
    backgroundColor = "white",
    dimLights = 0.6,
    loadingMessage = "Doing stuff ..."
  } = props;
  return (
    <Modal transparent={true} animationType="none" visible={show}>
      <View
        style={{
          flex: 1,
          alignItems: "center",
          justifyContent: "center",
          backgroundColor: `rgba(0,0,0,${dimLights})`
        }}
      >
        <View
          style={{
            padding: 13,
            backgroundColor: `${backgroundColor}`,
            borderRadius: 13
          }}
        >
          <ActivityIndicator animating={show} color={color} size="large" />
          <Text style={{ color: `${color}` }}>{loadingMessage}</Text>
        </View>
      </View>
    </Modal>
  );
};

and in your screen, in the render's return, just add it there as a child (please ignore the rest of the code, I put it there for context).

return (
<TouchableWithoutFeedback
  onPress={() => {
    Keyboard.dismiss();
  }}
>
  <View style={{ padding: 13, flex: 1}}>
    <ModalActivityIndicator show={screenIsWaiting} />
    <View
      style={{

where screenIsWaiting is just a state, for example

  const [screenIsWaiting, setScreenIsWaiting] = useState(false);

To test it you can add a button somewhere,

  <Button
    title="TestButton"
    onPress={async () => {
      setScreenIsWaiting(true);
      await sleep(5000);
      setScreenIsWaiting(false);
      ...
    }}
  />

where sleep is a function defined as

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

I found the sleep() idea on stackoverflow on another post.

You can of course also define the

<ModalActivityIndicator show={screenIsWaiting} ... />

only once in your App's root component and trigger it's display and props via a global state container like redux.

Solution 4 - Javascript

You can use StyleSheet.absoluteFill to shorten code. Add this to your render:

<View style={styles.container}>
  //... other code here
  {this.state.loading && <View
      style={{
        ...StyleSheet.absoluteFill,
        justifyContent: 'center',
        alignItems: 'center',
      }}>
      <ActivityIndicator />
  </View>}
</View>

Improvement:

You can also create a Loading component:

Loading.js

import React from 'react';
import {View, ActivityIndicator, StyleSheet} from 'react-native';

export const Loading = ({theme = 'white', size = 'large'}) => {
  const color = theme === 'white' ? '#00bdcd' : '#fff';
  return (
    <View
      style={{
        ...StyleSheet.absoluteFill,
        justifyContent: 'center',
        alignItems: 'center',
      }}>
      <ActivityIndicator size={size} color={color} />
    </View>
  );
};

Then use it anywhere you want

<View style={styles.container}>
   //... other code here
   // remember to import Loading component
   {this.state.loading && <Loading />}
</View>

Solution 5 - Javascript

There is a library available for this react-native-loading-spinner-overlay. You can simply install it using

npm install react-native-loading-spinner-overlay --save

and can import into your project using

import Spinner from 'react-native-loading-spinner-overlay';

Here is how to use it

<Spinner
  //visibility of Overlay Loading Spinner
  visible={this.state.loading}
  //Text with the Spinner 
  textContent={'Loading...'}
  //Text style of the Spinner Text
  textStyle={styles.spinnerTextStyle}
/>

enter image description here enter image description here

Solution 6 - Javascript

I suppose you should use Modal to overlay activity indicator. Following is an example:

<Modal
transparent={true}
animationType={'none'}
visible={loading}
onRequestClose={() => {console.log('close modal')}}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator
animating={loading} />
</View>
</View>
</Modal>

Solution 7 - Javascript

Add in view of loading

    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center'

Solution 8 - Javascript

STEP 1: Create the component for the spinner:

export const OverlaySpinner = () => {
 return (
    <View style={styles.spinnerView}>
      <ActivityIndicator size="large" color="#0000ff" />
    </View>
  );   
 };

STEP 2:

Create the style for the spinner view (using zIndex is very important to make sure the view is over everything on the screen):

spinnerView: {
    position: "absolute",
    zIndex: 1,
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "#F5FCFF88",
  },

STEP 3:

Make the initial state for the spinning component:

const [showSpinner, setshowSpinner] = useState(true);

STEP 4:

Use the component and don't forget to import it (don't forget to dismiss the keyboard on submit)

{showSpinner && <OverlaySpinner />}

Solution 9 - Javascript

set in View of Activity Indicator

position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, alignItems: 'center', justifyContent: 'center'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionvijaystView Question on Stackoverflow
Solution 1 - JavascriptG0dsquadView Answer on Stackoverflow
Solution 2 - Javascriptykay says Reinstate MonicaView Answer on Stackoverflow
Solution 3 - JavascriptGabriel P.View Answer on Stackoverflow
Solution 4 - JavascriptTony NguyenView Answer on Stackoverflow
Solution 5 - Javascriptsnehal agrawalView Answer on Stackoverflow
Solution 6 - JavascriptSanaur RahmanView Answer on Stackoverflow
Solution 7 - Javascriptuser13784257View Answer on Stackoverflow
Solution 8 - JavascriptEDMOND GView Answer on Stackoverflow
Solution 9 - Javascriptuser11716837View Answer on Stackoverflow