Implementing multiple Progress.bar in react-native - react-native

I want to achieve the WhatsApp stories like effect, where the number of progress bars on top are equal to the number of stories.
I'm using react-native-progress/bar library to achieve this effect, but I'm finding a way that how can I run second progress bar when first ends.
Actually progress of Progress.bar changes with the change of state.
What is an efficient way to do this by using a single state?
Here is code:
import React, { Component } from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import * as Progress from 'react-native-progress';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
image: {
width: 300,
height: 200,
},
});
export default class Example extends Component {
componentDidMount() {
this.animate();
}
constructor(props) {
super(props);
this.state = {
progress: 0
};
}
animate() {
let progress = 0;
this.setState({ progress });
let myInterval = setInterval(() => {
if (progress > 1) {
progress = 1;
clearInterval(myInterval);
} else {
progress += 0.01;
}
this.setState({ progress });
}, 20)
}
render() {
return (
<View style={styles.container}>
<View style={{flexDirection:'row'}} >
<Progress.Bar
key={'0'}
style={styles.progress}
progress={this.state.progress}
indeterminate={false}
/>
<Progress.Bar
key={'1'}
style={styles.progress}
progress={this.state.progress}
indeterminate={false}
/>
</View>
</View>
);
}
}

Related

automatic scrolling in code for PDF using React Native and react-native-pdf

I'm a bit new to React Native programming, and I'm working on implementing an autoscroll feature for PDFs. For example, in some cases, I want to automatically scroll a PDF down x pages and then scroll at a desired speed. I followed this tutorial here here which works for just normal data, but when I used a object from react-native-pdf, it does not seem to scroll anymore. I'm wrapping the PDF object inside a ScrollView and can confirm that the scrolling code is being called. Can anyone suggest a solution or explain why this does not work with the PDF? Thanks so much!
I've also attached my code below if that helps. Currently, the PDF displays but is not autoscrolling at all.
import React from 'react';
import {StyleSheet, Dimensions, View, ScrollView} from 'react-native';
import Pdf from 'react-native-pdf';
export default class PDFScroll extends React.Component {
constructor(props) {
super(props);
this.state = {
currentPosition: 0,
};
this.scrolling = this.scrolling.bind(this);
}
componentDidMount(){
this.activeInterval = setInterval(this.scrolling, 100);
}
componentWillUnmount(){
clearInterval(this.activeInterval);
}
scrolling() {
position = this.state.currentPosition + 50;
this.pdf.scrollTo({ x: position, animated: true });
// After position passes this value, snaps back to beginning
let maxOffset = 2000;
// Set animation to repeat at end of scroll
if (this.state.currentPosition > maxOffset) {
this.pdf.scrollTo({ x: 0, animated: false })
this.setState({ currentPosition: 0 });
}
else {
this.setState({ currentPosition: position });
}
}
render() {
const source = {
uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf',
cache: true,
};
return (
<View style={styles.container}>
<ScrollView
style={styles.scrollview}
horizontal={false}
bounces={true}
ref={(ref) => this.pdf = ref}
>
{
<Pdf
source={source}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`number of pages: ${numberOfPages}`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`current page: ${page}`);
}}
onError={error => {
console.log(error);
}}
onPressLink={uri => {
console.log(`Link presse: ${uri}`);
}}
style={styles.pdf}
/>
}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: 25,
},
pdf: {
flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
});

How to show loading progress or spinner in the middle of the screen with React Native?

I am developing React Native app.
I was able to solve all problems by myself but this is exception.
I am going to load another screen with bottom tab navigator.
For example, after user login to the app, it should show main home screen which has many pictures and many style sheet effects, icons. Because of that, after login confirm ( I mean after alert of the login confirm), the main home screen appears after a few seconds.
So I want to show some spinner in the login screen while loading main home screen in the background and when it is ready to show, erase spinner and show main home screen.
How can I do this?
My bottom tab navigator was simply created with createBottomTabNavigator() method.
So in your case you can do several things
You can use React Native Activity Indicator -> View
You can use Overlay Library -> react-native-loading-spinner-overlay -> View GitHub
If you like to make loading like facebook / instagram -> then use react-native-easy-content-loader -> View GitHub
Assume that you are using React Native Activity Indicator :
import { ActivityIndicator } from "react-native";
export default class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
}
//Get Home Screen Data API Action
componentDidMount() {
this.loadAPI(); // Call home screen get data API function
}
//Login API Function
loadAPI = () => {
this.setState({ isLoading: true }); // Once You Call the API Action loading will be true
fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json())
.then(responseText => {
// You can do anything accroding to your API response
this.setState({ isLoading: false }); // After getting response make loading to false
})
.catch(error => {});
};
render() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
{this.state.isLoading && <ActivityIndicator color={"#fff"} />}
</View>
);
}
}
If you want to hide all the view until loading finish like images, so you can use custom library instead of Activity Indicator.
I have created my custom Loader component. Using this you can display built in ActivityIndicator or your custom gif loader image with overlay.
Loader.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
Image,
ActivityIndicator
} from 'react-native';
class Loader extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: this.props.isLoading
}
}
static getDerivedStateFromProps(nextProps) {
return {
isLoading: nextProps.isLoading
};
}
render() {
return (
<Modal
transparent={true}
animationType={'none'}
visible={this.state.isLoading}
style={{ zIndex: 1100 }}
onRequestClose={() => { }}>
<View style={styles.modalBackground}>
<View style={styles.activityIndicatorWrapper}>
<ActivityIndicator animating={this.state.isLoading} color="black" />
{/* If you want to image set source here */}
{/* <Image
source={require('../assets/images/loader.gif')}
style={{ height: 80, width: 80 }}
resizeMode="contain"
resizeMethod="resize"
/> */}
</View>
</View>
</Modal>
)
}
}
const styles = StyleSheet.create({
modalBackground: {
flex: 1,
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#rgba(0, 0, 0, 0.5)',
zIndex: 1000
},
activityIndicatorWrapper: {
backgroundColor: '#FFFFFF',
height: 100,
width: 100,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around'
}
});
export default Loader
Now you can use it when you have to display loading indicator as below :
<Loader isLoading={this.state.isLoading} />
import { ActivityIndicator } from 'react-native';
export default class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner &&
<ActivityIndicator color={'#fff'} />
}
</View>
)
}
}
So you can show the SPinner for suppose when you have to load an API or something and when you get the response of api, you can set spinner loading value to false.
For eg :
import {View, ActivityIndicator } from 'react-native';
export default class MainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
spinner : true
}
}
componentDidMount(){
this.loadApi();
}
loadApi = async() => {
let result = axios.get('url').then((data) =>{
this.setState({spinner:false});
}
).catch((err) => this.setState({spinner:false})
}
render() {
return (
<View style={{flex : 1, justifyContent: 'center', alignItems: 'center',}}>
{
this.state.spinner? <ActivityIndicator color={'#fff'} />:<View><Text>Data loaded</Text></View>
}
</View>
)
}
}
you have to use ActivityIndicator you can have to load this activityindicator before getting data from the server , you have to check below code hope you will understand
import React, {useEffect, useState} from 'react';
import {ActivityIndicator, View, Dimensions} from 'react-native';
import HomeScreen from './Home';
const DataViewer = () => {
const [data, setData] = useState([]);
const {height, width} = Dimensions.get('window');
useEffect(() => {
fetch('http://example.com/movies.json')
.then(response => {
return response.json();
})
.then(myJson => {
setData(myJson);
});
});
return data.length > 0 ? (
<HomeScreen data={data} />
) : (
<View
style={{justifyContent: 'center', alignItems: 'center', height, width}}>
<ActivityIndicator size="large" color="#0000ff" />
</View>
);
};
export default DataViewer;
You can use the Activity indicator as the default loading animation. But you can also use Lottie files to implement custom loading screen animation on your project by installing npm i lottie-react-native or yarn add lottie-react-native

how to expand a component on click to full screen width and height with animation in reactnative

I have tried to implement the component expand to full screen in react native by using Layout animation in react-native but it was not good to look. Can any one help me in getting it?
changeLayout = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({ expanded: !this.state.expanded });
};
I expect to expand the component on click to full screen and again collapse it on click.
Set the initial value you want through the animation, obtain the screen width and height, and create a click function to execute.
This is an example that I made. Click this link if you want to run it yourself.
import React from 'react';
import { Animated, Text, View,Dimensions,Button } from 'react-native';
const screenwidth = Dimensions.get('screen').width
const screenheight = Dimensions.get('screen').height
class FadeInView extends React.Component {
state = {
fadeAnim: new Animated.Value(50),
fadeAnim2: new Animated.Value(50),
}
componentDidMount() {
}
animatebutton() {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: screenheight,
duration: 10000, // Make it take a while
}
).start();
Animated.timing( // Animate over time
this.state.fadeAnim2, // The animated value to drive
{
toValue: screenwidth,
duration: 10000, // Make it take a while
}
).start(); // Starts the animation
}
render() {
let { fadeAnim,fadeAnim2 } = this.state;
return (
<Animated.View // Special animatable View
style={{
...this.props.style,
height: fadeAnim,
width : fadeAnim2
}}
>
{this.props.children}
</Animated.View>
);
}
}
// You can then use your `FadeInView` in place of a `View` in your components:
export default class App extends React.Component {
constructor(props){
super(props);
this.state={
}
}
animatebutton(){
this.fade.animatebutton();
}
render() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}} >
<FadeInView style={{backgroundColor: 'powderblue'}} ref={ani => this.fade = ani}>
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
</FadeInView>
<Button title="go animate" onPress={() => this.animatebutton()}/>
</View>
)
}
}
OR
You can use LayoutAnimation that you want to use. Look at my example.
import React, {Component} from "react";
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
LayoutAnimation,
} from 'react-native';
class App extends Component {
constructor() {
super();
this.state = {
check: false,
}
}
onPresscheck() {
// Uncomment to animate the next state change.
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
// Or use a Custom Layout Animation
// LayoutAnimation.configureNext(CustomLayoutAnimation);
this.setState({ check : !this.state.check});
}
render() {
var middleStyle = this.state.check === false ? {width: 20,height:20} : {width: "100%",height:"100%"};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={() => this.onPresscheck()}>
<Text>pressbutton</Text>
</TouchableOpacity>
<View style={[middleStyle, {backgroundColor: 'seagreen'}]}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
button: {
width:"100%",
height: 60,
backgroundColor: 'blue',
alignItems: 'center',
justifyContent: 'center',
margin: 8,
},
});
export default App;
Please refer to this blog :
https://dev-yakuza.github.io/en/react-native/react-native-animatable/
Also, try using this library. Use any animation type you want and render them.
Happy coding :)

Force unmounting on screen change

I recently integrated React Redux and Redux Thunk into my application in the hope that it would better allow me to manage state across screens.
However, using my navigation library (react native router flux), when ever I navigate between screens I get warnings of trying to set state across unmounted components and I am not sure what I would even need to unmount in componentWillUnmount as no calls should happen after a screen navigation.
My question then is, how can I force unmount everything on componentWillUnmount? Is there something built into React Native that I should use? Or, in my navigation library?
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import * as Font from 'expo-font'
class CustomText extends Component {
async componentDidMount() {
await Font.loadAsync({
'varelaround-regular': require('../../../assets/fonts/varelaround-regular.ttf'),
'opensans-regular': require('../../../assets/fonts/opensans-regular.ttf'),
'opensans-bold': require('../../../assets/fonts/opensans-bold.ttf'),
});
this.setState({ fontLoaded: true });
}
state = {
fontLoaded: false,
};
setFontType = type => {
switch (type) {
case 'header':
return 'varelaround-regular';
case 'bold':
return 'opensans-bold';
default:
return 'opensans-regular';
}
};
render() {
const font = this.setFontType(this.props.type ? this.props.type : 'normal');
const style = [{ fontFamily: font }, this.props.style || {}];
const allProps = Object.assign({}, this.props, { style: style });
return (
<View>
{
this.state.fontLoaded ? (
<Text {...allProps}>{this.props.children}</Text>
) : <Text></Text>
}
</View>
);
}
}
export default CustomText;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
And one of my screens:
import React from "react";
import { ActivityIndicator, Image, StyleSheet, View } from "react-native";
import { Actions } from "react-native-router-flux";
import { connect } from "react-redux";
import * as profile from "../actions/profile";
import {
CustomText
} from "../components/common/";
class Home extends React.Component {
componentDidMount() {
this.props.loadProfile();
}
renderScreen() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 0.3 }}>
<CustomText type="header" style={styles.headerTextStyle} onPress={() => Actions.home()}>
Hello {this.props.name}!
</CustomText>
</View>
</View>
);
}
renderWaiting() {
return (
<GradientBackground type="purple">
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<ActivityIndicator size="large" color="#FFF" />
</View>
</GradientBackground>
);
}
render() {
return (
<View style={{ flex: 1 }}>
{this.props.isLoading == true
? this.renderWaiting()
: this.renderScreen()}
</View>
);
}
}
function mapStateToProps(state) {
return {
name: state.profile.profile.friendly_name,
isLoading: state.profile.isLoading,
error: state.profile.error
};
}
function mapDispatchToProps(dispatch) {
return {
loadProfile: () => dispatch(profile.loadProfile())
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Home);
const styles = StyleSheet.create({
headerTextStyle: {
color: "#FFFFFF",
fontSize: 40,
textAlign: "center",
marginVertical: 50
},
basicViewStyle: {
flex: 1
}
});

React Native `alignItems: 'flex-end'` hides content in TabBarIOS component

This question is similar to this one however I have different requirements. I have a <TabBarIOS> component that renders a <Camera> from react-native-camera. I need to place a button to take a picture at the bottom of the <Camera> component but above the <TabBarIOS> component.
index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
TabBarIOS,
ScrollView,
StyleSheet,
Text,
View
} from 'react-native';
import CameraTab from './views/CameraTab.ios.js';
import FilesTab from './views/FilesTab.ios.js';
import Icon from 'react-native-vector-icons/MaterialIcons';
export default class MyApp extends Component {
constructor(props) {
super(props);
this.state = {
selectedTab: 'cameraTab'
};
};
_renderContent() {
switch (this.state.selectedTab) {
case "filesTab":
return <FilesTab style={styles.tabContent}></FilesTab>;
case "cameraTab":
return <CameraTab style={styles.tabContent}></CameraTab>;
case "settingsTab":
return <View style={styles.tabContent}></View>;
default:
return <View style={styles.tabContent}></View>;
}
};
render() {
return (
<TabBarIOS
tintColor="#3498db"
barTintColor="#ecf0f1">
<Icon.TabBarItemIOS
title="Files"
iconName="folder"
selected={this.state.selectedTab === "filesTab"}
onPress={() => {
this.setState({
selectedTab: "filesTab",
});
}}>
{this._renderContent()}
</Icon.TabBarItemIOS>
<Icon.TabBarItemIOS
title="Camera"
iconName="photo-camera"
badge={this.state.notifCount > 0 ? this.state.notifCount : undefined}
selected={this.state.selectedTab === "cameraTab"}
onPress={() => {
this.setState({
selectedTab: "cameraTab",
notifCount: this.state.notifCount + 1,
});
}}>
{this._renderContent()}
</Icon.TabBarItemIOS>
<Icon.TabBarItemIOS
title="Settings"
iconName="settings"
selected={this.state.selectedTab === 'settingsTab'}
onPress={() => {
this.setState({
selectedTab: "settingsTab",
presses: this.state.presses + 1
});
}}>
{this._renderContent()}
</Icon.TabBarItemIOS>
</TabBarIOS>
);
}
}
var styles = StyleSheet.create({
tabContent: {},
});
AppRegistry.registerComponent('myapp', () => myApp);
CameraTab.ios.js
import React, { Component } from 'react';
import {
Dimensions,
StyleSheet,
Text,
View
} from 'react-native';
import Camera from 'react-native-camera';
export default class CameraTab extends Component {
constructor(props) {
super(props);
this.state = {};
};
render() {
return (
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}>
</Camera>
);
}
takePicture() {
this.camera.capture()
.then((data) => console.log(data))
.catch(err => console.error(err));
}
}
var styles = StyleSheet.create({
preview: {
flex: 1,
flexDirection: 'row',
alignItems: 'flex-end',
height: Dimensions.get('window').height,
width: Dimensions.get('window').width
},
capture: {
backgroundColor: '#fff',
borderRadius: 5,
color: '#000',
height: 20
}
});
module.exports = CameraTab;
I've tried various things but the capture button is always hidden when alignItems: 'flex-end' is in the container component's style.
It should look something like this:
Edit: I've discovered this issue that describes a workaround (placing the button component outside of the camera component). According to RN's docs on Height and Width it seems that this solution will work for all screen dimensions. However this doesn't work for me because I want a Subview with icons inside the camera.
OK, finally fixed it. I think the problem had to do with the height and width in the preview style. Working code:
import React, { Component } from 'react';
import {
Dimensions,
StyleSheet,
Text,
TouchableHighlight,
View
} from 'react-native';
import Camera from 'react-native-camera';
import Icon from 'react-native-vector-icons/Ionicons';
export default class CameraTab extends Component {
constructor(props) {
super(props);
this.state = {};
};
render() {
return (
<View style={styles.container}>
<Camera
ref={(cam) => {
this._camera = cam;
}}
style={styles.preview}
aspect={Camera.constants.Aspect.fill}
captureTarget={Camera.constants.CaptureTarget.disk}>
<TouchableHighlight
style={styles.cameraButton}
onPress={this._takePicture.bind(this)}>
<Icon name="ios-qr-scanner" size={55} color="#95a5a6" />
</TouchableHighlight>
</Camera>
</View>
);
}
_takePicture() {
this._camera.capture()
.then((data) => {
console.log(data)
})
.catch((err) => {
console.error(err)
});
}
}
var styles = StyleSheet.create({
cameraButton: {
flex: 0,
flexDirection: 'row',
marginBottom: 60,
},
container: {
flex: 1,
},
preview: {
flex: 1,
flexDirection: 'row',
alignItems: 'flex-end',
justifyContent: 'space-around'
},
});
module.exports = CameraTab;