How to swipe content in React Native - react-native

I am new to React Native and I have given a swipe task.
Swipe should change only the content of a view not the entire page
The swipe action should be tracked in dots bar.
I found two packages which are React Native Tab View and react-page-transitions. I am thinking about manipulating one of them to achieve such action or is there a better way? What is the best practice in swipe?
First Content
Second Content (frist content swiped)

I responded to a similar question and recommended react-native-swiper as it has the swiping functionality built in out of the box (this isnt enabled for web):
import React, { useState } from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import Swiper from 'react-native-swiper';
import {
colorGenerator,
colorManipulators,
} from '#phantom-factotum/colorutils';
const totalItems = 4;
export default function App() {
const DATA = colorGenerator(totalItems).map((color, index) => ({
color,
textColor: colorManipulators.darkenColor(color, 0.45),
title: 'Item' + (index + 1),
}));
return (
<View style={styles.container}>
<Swiper style={styles.wrapper} showsButtons={true} horizontal={true}>
{DATA.map((item, i) => {
return (
<View
style={[styles.item, { backgroundColor: item.color }]}
key={item.title}>
<Text style={[styles.text, { color: item.textColor }]}>
{item.title}
</Text>
</View>
);
})}
</Swiper>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
wrapper: {
// flex: 1,
},
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 30,
fontWeight: 'bold',
},
});
Here's the demo

Related

Touching two buttons at once in React Native

I am trying to make a simple game/task that requires a user to tap the left button, the right button, or both at about the same time. However, it seems like React Native prevents two buttons from being pressed down at the same time.
import React, { useState } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [leftButtonTaps, setLeftButtonTaps] = useState(0)
const [rightButtonTaps, setRightButtonTaps] = useState(0)
return (
<View style={styles.container}>
{leftButtonTaps}{" "}
{rightButtonTaps}
<TouchableOpacity onPress={() => setLeftButtonTaps((prev) => prev + 1)}>
<View style={styles.button}>Left</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {setRightButtonTaps((prev) => prev + 1)}}>
<View style={styles.button}>Right</View>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
flexDirection: "row"
},
button: {
backgroundColor: "blue",
height: 50,
width: 100,
marginTop: 300,
color: "white",
alignItems: "center",
justifyContent: "center",
marginLeft: 10,
marginRight: 10
}
});
I have tried importing TouchableOpacity from the react native gesture handler, but the results are the same. I have tried switching the onPress event to onPressIn, and that seems to work the same.
Is there any solution to this?
Edit: I have read that panresponder can solve this problem, but I can't seem to figure out how.

Text strings must be rendered within a <Text> component. When creating a button

I'm new to react native and trying to create a button, here is my StartScreen:
import React from 'react' import Background from '../components/Background' import AppButton from '../components/AppButton'
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />;
</Background>
) }
Here is my AppButton:
import React from 'react'
import { StyleSheet, TouchableOpacity, Text } from "react-native";
export default function AppButton ({ onPress, title, size, backgroundColor }) {
return (
<TouchableOpacity
onPress={onPress}
style={[
styles.appButtonContainer,
size === "sm" && {
paddingHorizontal: 8,
paddingVertical: 6,
elevation: 6
},
backgroundColor && { backgroundColor }
]}
>
<Text style={[styles.appButtonText, size === "sm" && { fontSize: 14 }]}>
{title}
</Text>
</TouchableOpacity>
)
};
const styles = StyleSheet.create({
screenContainer: {
flex: 1,
justifyContent: "center",
padding: 16
},
appButtonContainer: {
elevation: 8,
backgroundColor: "#009688",
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 12
},
appButtonText: {
fontSize: 18,
color: "#fff",
fontWeight: "bold",
alignSelf: "center",
textTransform: "uppercase"
}
});
Here is my Background:
import React from 'react'
import { ImageBackground, StyleSheet, KeyboardAvoidingView } from 'react-native'
import { theme } from '../core/theme'
export default function Background({ children }) {
return (
<ImageBackground style={styles.background}>
<KeyboardAvoidingView style={styles.container} behavior="padding">
{children}
</KeyboardAvoidingView>
</ImageBackground>
)
}
const styles = StyleSheet.create({
background: {
flex: 1,
width: '100%',
backgroundColor: theme.colors.surface,
},
container: {
flex: 1,
padding: 20,
width: '100%',
maxWidth: 340,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
})
When I try to run the application in my Android phone I get the following error:
Error: Text strings must be rendered within a component.
Blockquote
But I cant figure out where this error happens. Can someone spot the mistake?
You have an unnecessary semicolon (;) in your StartScreen JSX, remove it.
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />
</Background>
); }

Center alignment of React-Native ScrollView with custom starting position

Could you please look into what i'm missing with scrollview configuration.
I'm trying to create a scrollview animation with starting card-child offset by half of device-width, then when the user scrolls, it should align center and as should other rest of the scrollview-children
Basically all children when scrolled should align in center. Also first child should start at the end of the device width.
progress so far -> https://snack.expo.io/#sefeniyuk/scrollview-alignment
thank you.
import * as React from 'react';
import { Text, View, StyleSheet, ScrollView, Dimensions, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
const { width } = Dimensions.get('window');
const cardPaddingHorizontal = 2;
const cardWidth = width - cardPaddingHorizontal * 2;
const cardleftOffset = width - cardWidth / 3.5;
const initialCardShown = width - cardleftOffset;
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
scrollEventThrottle={1}
style={styles.style}
contentContainerStyle={styles.contentContainerStyle}
snapToAlignment="center"
decelerationRate="fast"
>
{[1, 2, 3, 4].map((num, i) => {
return (
<TouchableOpacity key={i} style={styles.card}>
<View style={styles.content}>
<Text style={styles.text}>{num}</Text>
</View>
</TouchableOpacity>
);
})}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
contentContainerStyle: {
width: cardWidth * 4
},
style: {
paddingLeft: cardleftOffset
},
card: {
backgroundColor: 'red',
width: cardWidth,
height: cardWidth,
margin: cardPaddingHorizontal,
elavation: 10
},
content: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
text: {
fontSize: 40,
color: 'white'
}
});
You can use react state hooks in functional components. You can either a give width for the starting scroll position or the best way is to use
scrollViewRef.current.scrollToIndex({ index: "index-of-item" })
import React, {useRef} from 'react'
const App = () => {
const scrollViewRef = useRef();
return (
<ScrollView horizontal={true} ref={scrollViewRef}
onContentSizeChange=
{() => scrollViewRef.current.scrollTo({x: giveWidth, y:
giveHeight, animated: true})}>
.
.
.
.
</ScrollView>
);
}

Progress Dialog in ReactNative

I'm pretty new to ReactNative world. Im struggling to find an api or a library that shows the Progress Dialog as below in React Native. I believe ActivityIndicator can be used, but it does not show as overlay. Can anyone help me how can I show as an overlay using styles or if there is good library to make this.
Thanks
Here is the code to Open Prgressbar:
import React from 'react';
import { Modal, View, Text, ActivityIndicator, Button } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { isProgress: false }
}
openProgressbar = () => {
this.setState({ isProgress: true })
}
render() {
return (
this.state.isProgress ?
<CustomProgressBar />
:
<View style={{ flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' }}>
<Button title="Please click here to Open ProgressBar" onPress={this.openProgressbar} />
</View>
);
}
}
const CustomProgressBar = ({ visible }) => (
<Modal onRequestClose={() => null} visible={visible}>
<View style={{ flex: 1, backgroundColor: '#dcdcdc', alignItems: 'center', justifyContent: 'center' }}>
<View style={{ borderRadius: 10, backgroundColor: 'white', padding: 25 }}>
<Text style={{ fontSize: 20, fontWeight: '200' }}>Loading</Text>
<ActivityIndicator size="large" />
</View>
</View>
</Modal>
);
Expo url for live demo
https://snack.expo.io/#jitendra.mca13/progress-bar-demo
I would approach this by using the React Native Modal component with two Views.
This solution is a React solution and not native, so you will need to style your Modal accordingly for each platform.
import React from 'react';
import {
Modal,
View,
StyleSheet,
Text,
ActivityIndicator
} from 'react-native';
const ProgressDialog = ({ visible }) => (
<Modal
visible={visible}
>
<View style={styles.container}>
<View style={styles.content}>
<Text style={styles.title}>Please Wait</Text>
<View style={styles.loading}>
<View style={styles.loader}>
<ActivityIndicator size="large" />
</View>
<View style={styles.loadingContent}>
<Text>Loading</Text>
</View>
</View>
</View>
</View>
</Modal>
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, .5)',
alignItems: 'center',
justifyContent: 'center',
},
content: {
padding: 35,
backgroundColor: 'white'
},
title: {
fontSize: 18,
fontWeight: 'bold',
},
loading: {
flexDirection: 'row',
alignItems: 'center',
},
loader: {
flex: 1,
},
loadingContent: {
flex: 3,
fontSize: 16,
paddingHorizontal: 10,
}
})
export default ProgressDialog;
Here's a demo on Expo, of course you will probably want to tweak the CSS.
Android & iOS solution
Create a directory called ProgressDialog
Create index.ios.js and index.android.js
Paste the above code into both index.ios.js and index.android.js
Make CSS changes for iOS
You can use the below npm package which is a very easy and attractive loader with many options.
https://github.com/maxs15/react-native-spinkit
import React from 'react';
import { StyleSheet, View } from "react-native";
import Spinner from "react-native-spinkit";
export default LoadingCmpBig = props => {
return (
<View style={styles.container}>
<StatusBar barStyle="default" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
//backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}
});
You can use this component and use it where you want to show the Progress. You just have to maintain the state for visible the loading or not in your render function of the component.

Text wrap with chevron on right in React Native ListView item renderer

I am trying to have a list view show up that looks similar to this. The problem I am trying to solve is regarding word wrapping of the label. I do have it working with the code below, but it feels like a hack and doesn't work with device rotation. There has to be a way to do it without using Dimensions and styling.
Here is what I have.
import React, { Component } from 'react';
import {
StyleSheet,
Dimensions,
TouchableOpacity,
Text,
View
} from 'react-native';
import Moment from 'moment'
import Icon from 'react-native-vector-icons/FontAwesome';
class ProjectListItemRenderer extends Component {
componentDidMount() {
//alert(Dimensions.get('window').height)
}
render() {
return (
<View style={styles.projectRow}>
<View style={{width: Dimensions.get('window').width - 50}}>
<Text style={styles.itemName}>{this.props.name}</Text>
<Text style={styles.itemDetails}>{`${Moment(this.props.lastUpdated).fromNow()}`}</Text>
</View>
<View style={styles.moreContainer}>
<Icon name="chevron-right" size={15} style={styles.moreIcon} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
projectRow: {
flexDirection: 'row',
justifyContent: 'flex-start',
padding: 15,
},
itemName: {
fontSize: 18,
color: '#4A90E2',
},
itemDetails: {
fontSize: 12,
color: '#BBBBBB',
},
moreContainer: {
justifyContent: 'center',
alignItems: 'center'
},
moreIcon: {
color: "#d6d7da"
}
});
module.exports = ProjectListItemRenderer;
The other option I tried was absolute positioning, with the label being 20px from the right, and then absolute positioning the chevron on the right. The problem I ran into there was trying to figure out the height of the individual listItem renderer after it is rendered (and word wrapped).
The problem comes from having flexDirection: 'row' in the View containing your text. This makes the text overflow to the right instead of wrapping. If you want your text to wrap, the containing View must have flexDirection: 'column' in the style.
I've modified your code accordingly:
import React, { Component } from 'react';
import {
StyleSheet,
Dimensions,
TouchableOpacity,
Text,
View
} from 'react-native';
import Moment from 'moment'
import Icon from 'react-native-vector-icons/FontAwesome';
class ProjectListItemRenderer extends Component {
componentDidMount() {
//alert(Dimensions.get('window').height)
}
render() {
return (
<View style={styles.projectRow}>
<View style={styles.projectText}>
<Text style={styles.itemName}>{this.props.name}</Text>
<Text style={styles.itemDetails>
{`${Moment(this.props.lastUpdated).fromNow()}`}
</Text>
</View>
<View style={styles.moreContainer}>
<Icon name="chevron-right" size={15} style={styles.moreIcon} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
projectText: {
flex: 1,
flexDirection: 'column'
},
projectRow: {
flexDirection: 'row',
justifyContent: 'flex-start',
padding: 15,
},
itemName: {
fontSize: 18,
color: '#4A90E2',
},
itemDetails: {
fontSize: 12,
color: '#BBBBBB',
},
moreContainer: {
justifyContent: 'center',
alignItems: 'center'
},
moreIcon: {
color: "#d6d7da"
}
});
module.exports = ProjectListItemRenderer;
The only difference is I replaced {width: Dimensions.get('window').width - 50} with {flex: 1, flexDirection: 'column'}.