React native fetching data from server using card view - javascript

I want to fetch data from a server using card view react native but when I open activity it's still loading, where is the mistake in my code?
renderItem = ({ item }) => {
return (
<Card>
<CardItem cardBody>
<Image source={{ uri: 'http://bprwasa.com/assets/frontend/images/gallery/kpo.jpg' }} style={{ height: 200, width: null, flex: 1 }} />
</CardItem>
<CardItem>
<Body>
<Text>
{item.nama_wil}
</Text>
</Body>
</CardItem>
</Card>
)}
and this
render() {
return (
this.state.isLoading
?
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size='large' color='#330066' animating />
</View>
:
<Container>
<Content>
{this.state.dataSource}
{this.renderItem}
</Content>
</Container>
)}}

In your case the problem is you are not setting animating property of ActivityIndicator to false.
however it is also important to note that there is still a bug until react-native version 0.58.3, check this
Solution
Use this reusable component it has the workaround { opacity: this.state.showActivityIndicator ? 1 : 0 }
Make sure you set its property showActivityIndicator to true and false.
import React, { Component } from "react";
import { ActivityIndicator, StyleSheet } from "react-native";
export default class ActivityProgress extends Component {
constructor(props) {
super(props);
this.state = {
showActivityIndicator: props.showActivityIndicator
};
}
componentDidUpdate(prevProps) {
if (this.props.showActivityIndicator != prevProps.showActivityIndicator) {
this.setState({
showActivityIndicator: this.props.showActivityIndicator
});
}
}
render() {
return (
<ActivityIndicator
size={isAndroid() ? 100 : "large"}
color="red"
animating={true}
style={[
{ opacity: this.state.showActivityIndicator ? 1 : 0 },
styles.spinnerLoading
]}
/>
);
}
}
const styles = StyleSheet.create({
spinnerLoading: {
position: "absolute",
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: "center",
justifyContent: "center"
}
});
Hope this helps.!

Related

React Native - add a masked circle overlay over image

How do I go about adding an opaque circular overlay over an image in React Native? Similar to the instagram image picker:
as trivial a task this may seem, I've had a world of trouble replicating this. Any suggestions?
As someone mentioned in the comments, the way to achieve this is with React Native Masked View.
Install it in your project by running:
npm install -S #react-native-community/masked-view
or
yarn add #react-native-community/masked-view
Then you can use it as follows. I've adapted the example from their README for you here:
import MaskedView from '#react-native-community/masked-view';
import React from 'react';
import { View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View
style={{
flex: 1,
backgroundColor: '#000000', // "Edge" background
maxHeight: 400,
}}
>
<MaskedView
style={{ flex: 1 }}
maskElement={
<View
style={{
// Transparent background mask
backgroundColor: '#00000077', // The '77' here sets the alpha
flex: 1,
}}
>
<View
style={{
// Solid background as the aperture of the lens-eye.
backgroundColor: '#ff00ff',
// If you have a set height or width, set this to half
borderRadius: 200,
flex: 1,
}}
/>
</View>
}
>
{/* Shows behind the mask, you can put anything here, such as an image */}
<View style={{ flex: 1, height: '100%', backgroundColor: '#324376' }} />
<View style={{ flex: 1, height: '100%', backgroundColor: '#F5DD90' }} />
<View style={{ flex: 1, height: '100%', backgroundColor: '#F76C5E' }} />
<View style={{ flex: 1, height: '100%', backgroundColor: '#2E6D3E' }} />
</MaskedView>
</View>
);
}
}
import React from 'react';
import {
SafeAreaView,
StyleSheet,
View,
Image,
Text
} from 'react-native';
const Test = () => {
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<Image
source={{
uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/old_logo.png'
}}
//borderRadius will help to make Round Shape
style={{
width: 200,
height: 200,
borderRadius: 200 / 2
}}
/>
<Text style={styles.textHeadingStyle}>
About React
</Text>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#e0dcdc',
},
textHeadingStyle: {
marginTop: 30,
fontSize: 40,
color: '#0250a3',
fontWeight: 'bold',
},
});
export default Test;
import React, { Component } from 'react';
import {
View,
StyleSheet,
Text,
ScrollView,
TouchableOpacity,
} from 'react-native';
import styles from './styles';
import { Circle, CustomHeader, CustomImage, CTNexaBold } from '../../components';
import translate from '../../translations/translate';
import { images, icons } from '../../assets'
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from 'react-native-responsive-screen';
import utils from '../../utils';
import { Colors } from '../../common';
import ImagePicker from 'react-native-image-crop-picker';
class UploadProfilePicture extends Component {
constructor(props) {
super(props);
this.state = {
profileImage: '',
isProfileImage: false,
};
}
componentDidMount() {
};
changeProfilePhoto() {
ImagePicker.openPicker({
width: 300,
height: 400,
cropping: true
}).then(image => {
this.setState({
profileImage: image.path,
isProfileImage: true,
})
});
}
render() {
const { profileImage, isProfileImage } = this.state
return (
<View style={styles.container}>
{utils.statusBar('dark-content', Colors.white)}
<CustomHeader
title={<CTNexaBold customStyle={styles.customStyle} >{translate("Upload Profile Picture")}</CTNexaBold>}
{...this.props}
/>
<View style={{ flex: 0.8, alignItems: 'center', justifyContent: 'center', marginBottom: 200 }} >
<View>
<Circle
width={wp('44%')}
height={wp('44%')}
borderRadius={wp('44%')}
borderColor={'#A28A3D'}
marginVertical={40}
marginHorizontal={70}
>
<CustomImage
style={styles.userAvatar}
// source={images.iconProfile}
source={ isProfileImage ? { uri: profileImage } : images.iconProfile }
/>
</Circle>
</View>
<View style={{ marginHorizontal: wp('10%') }} >
<TouchableOpacity onPress={()=>this.changeProfilePhoto()} >
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }} >
<CTNexaBold customStyle={styles.profileText} >Change Profile Photo</CTNexaBold>
<CustomImage
style={styles.containerCustomImage}
source={icons.arrowRight}
/>
</View>
</TouchableOpacity>
</View>
</View>
<View style={{ flex: 0.2, alignItems: 'center', justifyContent: 'center', marginBottom: 20 }} >
<TouchableOpacity style={styles.saveButton} >
<CTNexaBold customStyle={styles.saveButtonText} >SAVE</CTNexaBold>
</TouchableOpacity>
</View>
</View>
);
}
}
export default UploadProfilePicture;

How can I make this custom button component reusable across different controls?

I have this custom component class that I apply to my React Native Buttons and it has the expected behavior of scaling in and out (adding animation to shrink and resize) which is the behavior I want. However, I want the same animation for other controls in my app like Cards for example. I was wondering, how can I change this class to make it more extensible?
Here's my code:
import React from "react";
import { StyleSheet, Text, TouchableWithoutFeedback, Animated} from "react-native";
import Colors from "./Colors";
import Fonts from "./Fonts";
export default class TouchableBounce extends React.Component {
constructor(props) {
super(props);
this.handlePressIn = this.handlePressIn.bind(this);
this.handlePressOut = this.handlePressOut.bind(this);
}
componentWillMount() {
this.animatedValue = new Animated.Value(1);
}
handlePressIn() {
Animated.spring(this.animatedValue, {
toValue: .5
}).start()
}
handlePressOut() {
Animated.spring(this.animatedValue, {
toValue: 1,
friction: 5,
tension: 40
}).start()
}
render() {
const animatedStyle = {
transform: [{ scale: this.animatedValue}]
}
const {
disabled,
text,
color,
backgroundColor,
style,
showArrow,
testID,
buttonStyle
} = this.props;
return (
<TouchableWithoutFeedback
onPressIn={this.handlePressIn}
onPressOut={this.handlePressOut}
disabled={disabled}
style={[styles.buttonContainer, style]}
testID={testID || `button_${text}`}
>
<Animated.View
style={[
styles.button,
disabled ? { opacity: 0.5 } : {},
{ backgroundColor },
buttonStyle,
animatedStyle
]}
>
<Text style={[styles.buttonText, { color }]}>{text.toUpperCase()}</Text>
{showArrow && (
<Text
style={{
fontSize: 20,
fontWeight: "bold",
color: "white",
fontFamily: "system font",
marginBottom: 1
}}
>
{" "}
→
</Text>
)}
</Animated.View>
</TouchableWithoutFeedback>
);
}
}
TouchableBounce.defaultProps = {
disabled : false,
color : Colors.white,
backgroundColor : Colors.mainAccent,
style : {},
showArrow : false,
testID : "",
buttonStyle : {}
}
const styles = StyleSheet.create({
buttonContainer: {
alignSelf: "stretch",
marginTop: 35,
marginBottom: 35
},
button: {
borderRadius: 4,
padding: 20,
flexDirection: "row",
alignItems: "center",
justifyContent: "center"
},
buttonText: {
textAlign: "center",
fontFamily: Fonts.montserratBold,
fontSize: 16
}
});
EDIT: I have a question on where I should make the change for nesting the component.Inside my Home render function there's this snippet
const card = active ? (
<ActiveCard purchase={active} />
) : (
<InactiveCard />
);
and inside my return of that render, there is this snippet
{!this.props.foo && (
<View>
<TouchableOpacity
testID={"TOUCHABLE_CARD"}
onPress={() => {
this.tapCard(active);
}}
>
{card}
</TouchableOpacity>
</View>
)}
Where should I wrap the TouchableBounce? In both places or one of those places?
Try passing them as children of TouchableBounce
<TouchableBounce>
<CardView/>
</TouchableBounce>
In the TouchableBounce render them as
<TouchableWithoutFeedback
onPressIn={this.handlePressIn}
onPressOut={this.handlePressOut}
disabled={disabled}
style={[styles.buttonContainer, style]}
testID={testID || `button_${text}`}
>
<Animated.View
style={[
styles.button,
disabled ? { opacity: 0.5 } : {},
{ backgroundColor },
buttonStyle,
animatedStyle
]}
>
{this.props.children}//Here is the cardview that you have sent
</Animated.View>
</TouchableWithoutFeedback>
Edit:
For clear understanding iam attaching a working demo Expo demo
and also the official docs React.Children

Modal won't show the image in react native

I have written a program in which I am showing a list of images in ScrollView when user clicks an image a modal is popped up and image would be shown in large size. But this is not working.
Modal is opening fine but it is not showing the image..
However I have checked the value of image in render method of Modal i.e. ImageViewer, value I am getting is a class object.
App:
import React, {Component} from 'react';
import {View,Modal, ScrollView, Image, TouchableOpacity, StyleSheet} from 'react-native';
import pic1 from './images/sl13.png';
import pic2 from './images/sl14.png';
import pic3 from './images/sl15.png';
import pic4 from './images/sl16.png';
import pic5 from './images/sl17.png';
class App extends Component {
Images = [pic1, pic2, pic3, pic4, pic5];
state = {
modalVisible: false,
}
image = null
close(){
this.setState({modalVisible: false});
}
constructor(props){
super(props);
this.close = this.close.bind(this);
}
showImage(path){
this.image = path;
this.setState({modalVisible: true});
}
render() {
return (
<View style={{alignItems:'center', justifyContent: 'center'}}>
<ScrollView>
{this.Images.map((item)=>{
return (
<TouchableOpacity key={item} onPress={(item)=>this.showImage(item)}>
<View style={{borderColor: 'red', borderWidth: 1, marginBottom: 10}}>
<Image style={{width: 200, height: 200}} source={item} />
</View>
</TouchableOpacity>
)
})}
</ScrollView>
<ImageViewer closeModal={()=>this.close()} modalVisible={this.state.modalVisible} image={this.image}/>
</View>
);
}
}
Modal:
class ImageViewer extends Component {
render() {
console.log(this.props.image) //Checking Value here
return (
<Modal
style={{top: '50%', left: '50%', transform: 'translate(-50%, -50%) !important'}}
animationType='fade'
transparent={true}
onRequestClose={()=>this.props.closeModal()}
visible={this.props.modalVisible}
>
<View style={{flex:1 ,alignItems: 'center', justifyContent: 'center', backgroundColor:'#00000069'}}>
<View style={{padding:20 , backgroundColor:'#fff', borderRadius: 10}}>
<Image style={{width: 400, height: 600}} source={this.props.image} />
</View>
</View>
</Modal>
)
}
}
export default App;
both are in same file..
Screenshots :
Normal : https://imgur.com/deai02Y.jpg
Clicked on Image: https://imgur.com/POuZlPU.jpg
On Touchableopacity onPress you are actually passing the onPress $event to showImage function instead of item. so correct way of doing it is
<View style={{alignItems:'center', justifyContent: 'center'}}>
<ScrollView>
{this.Images.map((item)=>{
return (
<TouchableOpacity key={item} onPress={()=>this.showImage(item)}>
<View style={{borderColor: 'red', borderWidth: 1, marginBottom: 10}}>
<Image style={{width: 200, height: 200}} source={item} />
</View>
</TouchableOpacity>
)
})}
</ScrollView>
<ImageViewer closeModal={()=>this.close()} modalVisible={this.state.modalVisible} image={this.image}/>
</View>
after app called write
constructor(props) {
super(props);
this.state = {
image : ''
};
}
and in showImage path
showImage(path){
this.setstate({image : path});
this.setState({modalVisible: true});
}
and in Imageviewer
<ImageViewer closeModal={()=>this.close()} modalVisible={this.state.modalVisible} image={this.state.image}/>

Showing list empty message at the center of the screen in a FlatList using ListHeaderComponent

I am using React-Native version 0.43.0 which does not support ListEmptyComponent of FlatList. Hence I am using ListHeaderComponent to render a view when the list is empty,
import React, { Component } from 'react';
import { Text, View, StyleSheet,FlatList } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {
listData: []
}
}
render() {
return (
<View style={styles.container}>
<FlatList
renderItem={() => null}
data={this.state.listData}
ListHeaderComponent={() => (!this.state.listData.length?
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
: null)
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1
},
emptyMessageStyle: {
textAlign: 'center',
//My current hack to center it vertically
//Which does not work as expected
marginTop: '50%',
}
});
As you can see from the image the text is not centered vertically
Any idea how to center it vertically in a FlatList?
I have already tried applying justifyContent, alignItems etc but no use.
This is a link to the snack.expo - https://snack.expo.io/S16dDifZf
Hope this will help you
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
disableVirtualization={false}
data={this.state.data}
renderItem={this.renderItem}
ListEmptyComponent={this.renderEmptyContainer()}
/>
}
/>
Place your UI in the renderEmptyContainer() method and boom, Empty container will show up whenever your list is empty
They fixed ListEmptyComponent in this pr https://github.com/facebook/react-native/pull/18206. But they will ship in 0.56.
UPDATE: Checkout the official doc ListEmptyComponent
You can add a style to the FlatList.
const styles = StyleSheet.create({
container: {
flex:1
},
listStyle: {
justifyContent: 'center'
},
emptyMessageStyle: {
textAlign: 'center',
}
});
render() {
return (
<View style={styles.container}>
<FlatList style={styles.listStyle}
renderItem={() => null}
data={this.state.listData}
ListHeaderComponent={() => (!this.state.listData.length ?
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
: null)}
/>
</View>
);
}
This will center the items in the list, when the list is not empty. You may have to apply another style (when the list is not empty), if you don't prefer the non empty style.
Link to snack.expo
Another option - without changing FlatList style - conditionally rendering FlatList based on this.state.listData.length
render() {
return (
<View style={styles.container}>
{
this.state.listData.length?
(<FlatList
renderItem={() => null}
data={this.state.listData}
/>)
:
(
<View style={styles.emptyListStyle}>
<Text style={styles.emptyMessageStyle}>The list is empty</Text>
</View>
)
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1
},
emptyListStyle: {
flex: 1,
justifyContent: 'center'
},
emptyMessageStyle: {
textAlign: 'center',
}
});
This is the snack.expo
You must combine props ListEmptyComponent with contentContainerStyle={{flex:1}} flex:1 will set the maximal height in the container and will allow you to center vertically. ie:
<FlatList
...
contentContainerStyle={customers.length === 0 && styles.centerEmptySet}
ListEmptyComponent={<EmptySetCustomer />}
/>
Note that you must set a condition to remove flex:1 when list is not empty. To allow scroller.
Hope it will help.
This resolve for me.
<FlatList
contentContainerStyle={{ flexGrow: 1,
justifyContent: "center",
alignItems: "center"}}
disableVirtualization={false}
data={this.state.data}
renderItem={this.renderItem}
ListEmptyComponent={this.renderEmptyContainer()}
/>
}
/>
As a temporary workaround you can conditionally set a style to the contentContainer to center only the empty set like this
<FlatList
contentContainerStyle={customers.length === 0 && styles.centerEmptySet}
data={customers}
renderItem={({ item, index }) => (
/// Your item here
)}
keyExtractor={(item, index) => {
return String(index);
}}
ListEmptyComponent={<EmptySetCustomer />}
/>
And styles like this
centerEmptySet: { justifyContent: 'center', alignItems: 'center', height: '100%' }
Then in 2-3 weeks we can update to 0.56 and remove the workaround
<FlatList
keyExtractor={(item) => item.id}
data={flatListItems}
ListEmptyComponent={<View style= {styles.EmptytextHeader}><Text style={styles.EmptyMassage}>No data found</Text></View>}
renderItem={({ item }) => {
return <View><Text>add Your Data</Text></View>
/>
}}
/>
const styles = StyleSheet.create({
EmptytextHeader: {
flex:1,
justifyContent:'center',
alignItems:'center'
},
EmptyMassage: {
color:'red',
fontWeight: '700',
fontSize: 16,
fontStyle: 'normal',
},
});
its working

How do I overlay ActivityIndicator in react-native?

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.
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>
}
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'
}
})
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>
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.
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}
/>
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 />}
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>
Add in view of loading
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
set in View of Activity Indicator
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
Here my code for a functional component for anyone looking to achieve this with nativebase as design system. useColorScheme is another hook I use for detecting dark mode.
import { Flex, Spinner } from "native-base"
import React from "react"
import useColorScheme from "../../hooks/useColorScheme"
export default function Loading() {
const colorScheme = useColorScheme()
return (
<Flex
position="absolute"
alignItems="center"
justifyContent="center"
top={0}
left={0}
right={0}
bottom={0}
backgroundColor={colorScheme === "dark" ? "coolBlack.500" : "white"}
>
<Spinner size="lg" color={colorScheme === "dark" ? "white" : "coolBlack.500"} />
</Flex>
)
}

Categories

Resources