Related
app.js
import { StatusBar } from "expo-status-bar";
import {
TouchableOpacity,
Button,
StyleSheet,
Alert,
SafeAreaView,
Text,
} from "react-native";
export default function App() {
let count = 5;
let counts = [count];
return (
<SafeAreaView style={styles.container}>
<Text style={styles.Text}>Earn Money</Text>
<TouchableOpacity
onPress={() => {
count += 0.25;
console.log(count);
}}
style={{
height: 70,
width: 130,
backgroundColor: "#ff5c5c",
alignSelf: "center",
top: 25,
}}
>
<Text
style={{
fontWeight: "900",
alignSelf: "center",
position: "relative",
top: 25,
}}
>
Earn 0.20$
</Text>
</TouchableOpacity>
<Text style={styles.Balance}>{count}</Text>
<StatusBar style="auto" />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Platform.OS === "android" ? 90 : 0,
paddingLeft: Platform.OS === "android" ? 10 : 0,
},
Text: {
justifyContent: "center",
alignSelf: "center",
color: "orange",
fontSize: 25,
fontWeight: "900",
},
Balance: {
justifyContent: "center",
alignSelf: "center",
color: "orange",
fontSize: 25,
fontWeight: "900",
top: 100,
},
});
So when I press touchableOpacity the count variable is supposed to add 0.25 to itself , That is working fine but the text
<Text style={styles.Balance}>{count}</Text>
is not updating.I would also want to know if the way I dispaly the variable count in <Text><Text/> is correct.
THe text is just showing 5 I have no prior experience with React native if you would help pls do.
React uses some hooks for updating the DOM you can't just use variables and expect it to update the DOM, in this instance you need to use useState hook
import { StatusBar } from "expo-status-bar";
import { useState} from "react";
import {
TouchableOpacity,
Button,
StyleSheet,
Alert,
SafeAreaView,
Text,
} from "react-native";
export default function App() {
let [count, setCount] = useState(0);
return (
<SafeAreaView style={styles.container}>
<Text style={styles.Text}>Earn Money</Text>
<TouchableOpacity
onPress={() => {
setCount(c => c + 0.5)
}}
style={{
height: 70,
width: 130,
backgroundColor: "#ff5c5c",
alignSelf: "center",
top: 25,
}}
>
<Text
style={{
fontWeight: "900",
alignSelf: "center",
position: "relative",
top: 25,
}}
>
Earn 0.20$
</Text>
</TouchableOpacity>
<Text style={styles.Balance}>{count}</Text>
<StatusBar style="auto" />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Platform.OS === "android" ? 90 : 0,
paddingLeft: Platform.OS === "android" ? 10 : 0,
},
Text: {
justifyContent: "center",
alignSelf: "center",
color: "orange",
fontSize: 25,
fontWeight: "900",
},
Balance: {
justifyContent: "center",
alignSelf: "center",
color: "orange",
fontSize: 25,
fontWeight: "900",
top: 100,
},
});
You can read this article to better understand react and how it works.
import { useState} from "react";
const [count,setCount]=useState(5) // 5 is default value
const [update,setUpdate]=useState(0) // add this
export default function App() {
let count = 5;
let counts = [count];
return (
<SafeAreaView style={styles.container}>
<Text style={styles.Text}>Earn Money</Text>
<TouchableOpacity
onPress={() => {
count += 0.25;
setCount(count) // add this
setUpdate(update+1) // add this
console.log(count);
}}
style={{
height: 70,
width: 130,
backgroundColor: "#ff5c5c",
alignSelf: "center",
top: 25,
}}
>
<Text
style={{
fontWeight: "900",
alignSelf: "center",
position: "relative",
top: 25,
}}
>
Earn 0.20$
</Text>
</TouchableOpacity>
<Text style={styles.Balance}>{count}</Text>
<StatusBar style="auto" />
</SafeAreaView>
);
}
import { Observer } from "mobx-react";
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
ImageBackground,
TouchableOpacity,
Image,
Platform,
Dimensions,
Clipboard,
} from "react-native";
import * as Progress from "react-native-progress";
import AppStore from "../../stores/AppStore";
import Iconpack from "../../utils/Iconpack";
import Theme from "../../utils/Theme";
import DeviceInfo from "react-native-device-info";
import CircularProgressBar from "./CircularProgressBar";
import { Shadow } from "react-native-shadow-2";
import Toast from "react-native-simple-toast";
import { BoxShadow } from "react-native-shadow";
import FastImage from "react-native-fast-image";
// import Clipboard from "#react-native-community/clipboard";
const hRem = AppStore.screenHeight / 812;
const wRem = AppStore.screenWidth / 375;
export class OtpDetails extends Component {
constructor() {
super();
this.state = {
progress: 0,
indeterminate: true,
clipboardText: "",
textInputText: "",
};
}
componentDidMount() {
this.animate();
}
animate() {
let progress = 0;
this.setState({ progress });
setTimeout(() => {
this.setState({ indeterminate: false });
const interval = setInterval(() => {
progress += Math.random() / 30;
if (progress > 1) {
progress = 1;
clearInterval(interval);
}
this.setState({ progress });
}, 600);
}, 600);
}
render() {
const shadowOpt = {
width: 160,
height: 170,
color: "#fff",
border: 2,
radius: 70,
opacity: 6,
x: 0,
y: 3,
};
const { myTitle } = this.props.route.params;
const setTextIntoClipboard = async () => {
await Clipboard.setString(myTitle);
Toast.show("OTP copied successfully!", 200);
};
const deviceName = DeviceInfo.getModel();
return (
<Observer>
{() => (
<View style={{ flex: 1 }}>
<FastImage
style={styles.container}
source={Iconpack.GLOBAL_BG}
resizeMode={FastImage.resizeMode.cover}
/>
<View style={styles.headerStyle}>
<TouchableOpacity
onPress={() => {
this.props.navigation.navigate("OtpScreen");
}}
>
<Image
style={styles.backButton}
source={Iconpack.GLOBAL_BACK_BUTTON}
/>
</TouchableOpacity>
<Text style={styles.headerTitle}>{myTitle}</Text>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity>
<Image
style={[styles.editTrashButton, { marginRight: 19 }]}
source={Iconpack.EDIT_ICON}
/>
</TouchableOpacity>
<TouchableOpacity>
<Image
style={styles.editTrashButton}
source={Iconpack.DELETE_ICON}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.circleOuter}>
{Platform.OS === "ios" ? (
<View style={styles.circleContainer}>
<Progress.Circle
style={{ alignItems: "center" }}
progress={this.state.progress}
indeterminate={this.state.indeterminate}
size={Dimensions.get("window").width * 0.561}
thickness={10}
borderWidth={0}
endAngle={10}
strokeCap="round"
color={"#354659"}
indeterminateAnimationDuration={2000}
unfilledColor={"#031830"}
/>
</View>
) : (
<Shadow
distance={20}
startColor={"rgba(27, 100, 206, 0.5)"}
radius={210}
safeRender={true}
>
<View style={styles.circleContainer}>
<Progress.Circle
style={{ alignItems: "center", overflow: "hidden" }}
progress={this.state.progress}
indeterminate={this.state.indeterminate}
size={Dimensions.get("window").width * 0.561}
thickness={10}
borderWidth={0}
endAngle={10}
strokeCap="round"
color={"#354659"}
indeterminateAnimationDuration={2000}
unfilledColor={"#031830"}
/>
</View>
</Shadow>
)}
<Text style={[styles.circleItem]}>{myTitle}</Text>
<TouchableOpacity
onPress={() => {
setTextIntoClipboard();
}}
style={styles.copyItem}
>
<Text style={styles.copyText}>TAP TO COPY</Text>
</TouchableOpacity>
</View>
{/* <View style={styles.circleOuter}>
<View style={styles.circleContainer}>
<Text style={styles.circleItem}>title</Text>
</View>
<TouchableOpacity
onPress={() => {
copyToClipboard();
}}
style={styles.copyItem}
>
<Text style={styles.copyText}>TAP TO COPY</Text>
</TouchableOpacity> */}
{/* </View> */}
</View>
)}
</Observer>
);
}
}
export default OtpDetails;
const styles = StyleSheet.create({
container: {
flex: 1,
position: "absolute",
top: 0,
right: 0,
left: 0,
bottom: 0,
backgroundColor: "#021831",
},
headerStyle: {
flexDirection: "row",
marginTop: hRem * 56,
marginHorizontal: wRem * 26.66,
justifyContent: "space-between",
alignItems: "center",
},
backButton: {
width: wRem * 12,
height: hRem * 21,
},
editTrashButton: {
width: wRem * 23,
height: hRem * 23,
},
headerTitle: {
...Theme.encodeSansMed2,
lineHeight: hRem * 16,
color: "#FFFFFF",
fontWeight: "600",
marginLeft: wRem * 50,
},
circleOuter: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
circleContainer: {
borderRadius:
Math.round(
Dimensions.get("window").width + Dimensions.get("window").height
) / 2,
width: Dimensions.get("window").width * 0.56,
height: Dimensions.get("window").width * 0.56,
justifyContent: "center",
backgroundColor: "black",
shadowColor: "rgba(27, 100, 206, 0.5)",
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 30,
shadowRadius: 30,
},
circleItem: {
color: "white",
...Theme.encodeSansMed7,
textAlign: "center",
position: "absolute",
width: "100%",
paddingBottom: 100,
},
copyItem: {
justifyContent: "center",
alignItems: "center",
marginTop: hRem * 64,
},
copyText: {
color: "#3D4756",
...Theme.encodeSansMed4,
},
});
I have added circular progress by using the react-native-progress library. I have implemented logic for moving bar for 30 sec but the thing is after 30 sec it stops, so I need to keep moving after 30 sec here my whole code.
Here is the logical part which I have added here...
constructor() {
super();
this.state = {
progress: 0,
indeterminate: true,
clipboardText: "",
textInputText: "",
};
}
componentDidMount() {
this.animate();
}
animate() {
let progress = 0;
this.setState({ progress });
setTimeout(() => {
this.setState({ indeterminate: false });
const interval = setInterval(() => {
progress += Math.random() / 30;
if (progress > 1) {
progress = 1;
clearInterval(interval);
}
this.setState({ progress });
}, 600);
}, 600);
}
I have tried several ways but nothing is happening also function will be welcome for this question. thanks in advance
I am having trouble getting these two forms to just show the number input from my Virtualized Keyboard. Essentially what is going on here is that I have a numeric keypad passing in the numbers from the virtualized keyboard and a currency component to be able to have the currency format (thousand commas, and decimals).
Here is the UI for better idea of what I'm trying to explain.
When I press the keypad it says this:
This is the error I get
Here is my code:
import React, { useState, useEffect, useCallback } from "react";
import {
ScrollView,
StyleSheet,
Image,
TouchableWithoutFeedback,
ImageBackground,
Dimensions,
View,
StatusBar,
SafeAreaView,
TextInput,
Keyboard
} from "react-native";
import { Block, Text, theme } from "galio-framework";
import VirtualKeyboard from 'react-native-virtual-keyboard';
import CurrencyInput from '../components/CurrencyInput';
import Button from '../components/Button'
import { HeaderHeight } from "../constants/utils";
const { height, width } = Dimensions.get("screen");
const Give = () => {
const [value, setValue] = useState(0);
const handleValueChange = useCallback(val => {
// eslint-disable-next-line
console.log(val);
setValue(val);
}, []);
return (
<View style={style.container}>
<SafeAreaView>
<Block style={style.allContainer}>
<Block style={style.numberContainer}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss()} accessible={false} >
<CurrencyInput
max={100000000}
onValueChange={handleValueChange}
style={style.inputNumber}
value={value}
/>
</TouchableWithoutFeedback>
</Block>
<VirtualKeyboard color='#000' pressMode='string' onPress={(val) => setValue(val)} />
<Button style={style.button}><Text style={style.buttonText}>Ofrendar</Text></Button>
</Block>
</SafeAreaView>
</View>
)
}
const style = StyleSheet.create({
container: {
marginTop: Platform.OS === 'android' ? -HeaderHeight : 0,
height: height,
flex: 1,
flexDirection: 'row',
backgroundColor: "#fff",
width: width
},
backgroundImage: {
width: width,
flex: 1,
resizeMode: "cover",
},
animationContainer: {
},
animationImage: {
height: 250,
aspectRatio: 1,
alignSelf: "center",
},
ofrenda: {
fontSize: 55,
textAlign: "center",
fontWeight: "bold",
marginBottom: 70
},
buttonText: {
color: "#FFF",
fontSize: 30,
fontWeight: "bold",
letterSpacing: 2
},
button: {
height: 60,
width: width - theme.SIZES.BASE * 6,
marginBottom: 30,
marginTop: 30,
backgroundColor: "#00a8ff",
borderWidth: 3,
borderRadius: 10,
borderColor: "#00a8ff",
shadowColor: "transparent"
},
bottomButton: {
position: 'absolute',
bottom: 30
},
numberContainer: {
},
inputNumber: {
fontSize: 50,
fontWeight: "bold"
},
allContainer: {
justifyContent: "center",
alignItems: "center",
height: height,
width: width,
alignSelf: "center"
}
});
export default Give;
There seems to be a un-changeable margin on views using the react-native-scrollable-tab-view module. I can seem to get my code to fit to page on the views nested inside the scrollable-tab-view component. Any ideas? here's the code of the page presented:
'use strict';
import React from 'react';
import {
StyleSheet,
View,
Image,
Text,
TextInput
} from 'react-native';
//dimensions
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
//modules/pages
var StepImage = require('../components/StepImage');
import Icon from 'react-native-vector-icons/FontAwesome';
import {Actions} from "react-native-router-flux";
var NavHeader = require('../components/Header');
var UserStat = require('../components/UserStat');
var UserCircle = require('../components/UserCircle');
var Button = require('../components/Button');
var Data = require('../stores/userDiets');
var NavigationBar = require('react-native-navbar');
var Profile = React.createClass({
getInitialState: function() {
return {
};
},
render: function() {
var Keywords = Data.diets;
return (
<View style={[styles.container]}>
<NavigationBar
style={{width: window.width}}
tintColor={'#50AE57'}
title={{title: 'Robert Greenfield', tintColor: 'white', style: {fontFamily: 'Nunito', fontSize: 18}}} />
<View style={[styles.header, this.border('red')]}>
<View style={[styles.userrow, this.border('red')]}>
<UserCircle source={require('../img/user/user.jpg')} style={styles.circle}/>
<View style={[styles.userinfo, this.border('orange')]}>
<View style={[styles.userstats, this.border('blue')]}>
<UserStat stat={3333} statTitle={'posts'} />
<UserStat stat={8888} statTitle={'achievements'} />
<UserStat stat={112} statTitle={'following'} />
<UserStat stat={'550K+'} statTitle={'followers'} />
</View>
<Icon.Button size={12} name="cogs" style={styles.edit} backgroundColor="#F4F4F4" onPress={this.loginWithFacebook}>
<Text style={styles.editText}>Edit Profile</Text>
</Icon.Button>
</View>
</View>
<View style={[styles.userBio, this.border('blue')]}>
<Text style={styles.userBioText}>The biggest #nutfree IG in the world. tag #nutfreenoms or #nomsy. To be featured, make an account at nomsy.co and post what you want shown! nomsy.co</Text>
</View>
<View style={styles.dietRow}>
{this.renderDiets(Keywords)}
</View>
</View>
</View>
);
},
renderDiets: function(diets) {
var that = this;
return diets.map(function(diet, i) {
return <View key={i} style={styles.box}><Text key={i} style={styles.userBioText}>{diet.name}</Text></View>
});
},
border: function(color) {
return {
//borderColor: color,
//borderWidth: 1,
}
}
});
var styles = StyleSheet.create({
box: {
margin: 2,
backgroundColor: '#56bf60',
borderRadius:2,
height: window.height/35,
padding: 3,
justifyContent: 'center'
},
dietRow:{
flexWrap: 'wrap',
flexDirection:'row',
height: window.height/20,
marginLeft: window.width/40,
width: window.width*0.96,
},
userBio: {
width: window.width*0.96,
alignItems: 'center',
marginLeft: window.width/80,
marginBottom: window.height/100
},
userBioText: {
color: 'black',
fontFamily: 'Nunito',
fontSize: 10
},
editText: {
color: 'white',
fontFamily: 'Nunito',
alignSelf: 'center'
},
edit: {
height: window.height/25,
justifyContent: 'center',
alignItems: 'center'
},
circle: {
width: window.width/5,
height: window.width/5,
borderRadius: window.width/10
},
userstats: {
flexDirection: 'row',
backgroundColor: 'white',
justifyContent: 'space-around',
marginBottom: window.height/100
},
userinfo: {
flexDirection: 'column',
backgroundColor: 'transparent',
width: window.width/1.4
},
userrow: {
flexDirection: 'row',
backgroundColor: 'transparent',
height: window.height/8,
justifyContent: 'space-around',
width: window.width
},
header: {
marginTop: window.height/50,
width: window.width,
flex: 0.9,
backgroundColor: 'white',
},
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'flex-start',
},
});
module.exports = Profile;
And here's what it looks like:
You have to set automaticallyAdjustContentInsets={false} in your ListView (or ScrollView). Details here:
https://github.com/skv-headless/react-native-scrollable-tab-view/pull/174
https://github.com/facebook/react-native/issues/721
https://facebook.github.io/react-native/docs/scrollview.html#automaticallyadjustcontentinsets
In React Native iOS, I would like to slide in and out of a like in the following picture.
In the following example, when a button is pressed, the Payment Information view pops up from the bottom, and when the collapse button is pressed, it goes back down and disappears.
What would be the correct and proper way to go about doing so?
Thank you in advance!
EDIT
Basically, you need to absolute-position your view to the bottom of the screen. Then you translate its y value to equal its height. (The sub view must have a specific height in order to know how much to move it)
Code:
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
Animated
} = ReactNative;
var isHidden = true;
class AppContainer extends Component {
constructor(props) {
super(props);
this.state = {
bounceValue: new Animated.Value(100), //This is the initial position of the subview
buttonText: "Show Subview"
};
}
_toggleSubview() {
this.setState({
buttonText: !isHidden ? "Show Subview" : "Hide Subview"
});
var toValue = 100;
if(isHidden) {
toValue = 0;
}
//This will animate the transalteY of the subview between 0 & 100 depending on its current state
//100 comes from the style below, which is the height of the subview.
Animated.spring(
this.state.bounceValue,
{
toValue: toValue,
velocity: 3,
tension: 2,
friction: 8,
}
).start();
isHidden = !isHidden;
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button} onPress={()=> {this._toggleSubview()}}>
<Text style={styles.buttonText}>{this.state.buttonText}</Text>
</TouchableHighlight>
<Animated.View
style={[styles.subView,
{transform: [{translateY: this.state.bounceValue}]}]}
>
<Text>This is a sub view</Text>
</Animated.View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
marginTop: 66
},
button: {
padding: 8,
},
buttonText: {
fontSize: 17,
color: "#007AFF"
},
subView: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#FFFFFF",
height: 100,
}
});
AppRegistry.registerComponent('AppContainer', () => AppContainer);
I know it is a little bit late, but thought it might be useful for someone. You should try out a component called rn-sliding-out-panel. It works awesomely. https://github.com/octopitus/rn-sliding-up-panel
<SlidingUpPanel
draggableRange={top: 1000, bottom: 0}
showBackdrop={true|false /*For making it modal-like*/}
ref={c => this._panel = c}
visible={ture|false /*If you want it to be visible on load*/}
></SlidingUpPanel>
And you can even open it from an external button:
<Button onPress={()=>{this._panel.transitionTo(1000)}} title='Expand'></Button>
You can install it via npm: sudo npm install rn-sliding-out-panel --save on your react-native root directory.
I hope it helps someone :D
I've created a reusable BottomSheet component that accepts any content.
This is how it looks like:
Here's the code (in TypeScript) of the BottomSheet component:
import * as React from 'react'
import {
Animated,
Easing,
Pressable,
StyleSheet,
useWindowDimensions,
View,
} from 'react-native'
const DEFAULT_HEIGHT = 300
function useAnimatedBottom(show: boolean, height: number = DEFAULT_HEIGHT) {
const animatedValue = React.useRef(new Animated.Value(0))
const bottom = animatedValue.current.interpolate({
inputRange: [0, 1],
outputRange: [-height, 0],
})
React.useEffect(() => {
if (show) {
Animated.timing(animatedValue.current, {
toValue: 1,
duration: 350,
// Accelerate then decelerate - https://cubic-bezier.com/#.28,0,.63,1
easing: Easing.bezier(0.28, 0, 0.63, 1),
useNativeDriver: false, // 'bottom' is not supported by native animated module
}).start()
} else {
Animated.timing(animatedValue.current, {
toValue: 0,
duration: 250,
// Accelerate - https://easings.net/#easeInCubic
easing: Easing.cubic,
useNativeDriver: false,
}).start()
}
}, [show])
return bottom
}
interface Props {
children: React.ReactNode
show: boolean
height?: number
onOuterClick?: () => void
}
export function BottomSheet({
children,
show,
height = DEFAULT_HEIGHT,
onOuterClick,
}: Props) {
const { height: screenHeight } = useWindowDimensions()
const bottom = useAnimatedBottom(show, height)
return (
<>
{/* Outer semitransparent overlay - remove it if you don't want it */}
{show && (
<Pressable
onPress={onOuterClick}
style={[styles.outerOverlay, { height: screenHeight }]}
>
<View />
</Pressable>
)}
<Animated.View style={[styles.bottomSheet, { height, bottom }]}>
{children}
</Animated.View>
</>
)
}
const styles = StyleSheet.create({
outerOverlay: {
position: 'absolute',
width: '100%',
zIndex: 1,
backgroundColor: 'black',
opacity: 0.3,
},
bottomSheet: {
position: 'absolute',
width: '100%',
zIndex: 1,
// Here you can set a common style for all bottom sheets, or nothing if you
// want different designs
backgroundColor: 'dodgerblue',
borderRadius: 16,
},
})
I put this code in a file named BottomSheet.tsx.
This is how you use the BottomSheet:
import * as React from 'react'
import {
Pressable,
SafeAreaView,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native'
import { BottomSheet } from './src/BottomSheet'
const App = () => {
const [showBottomSheet, setShowBottomSheet] = React.useState(false)
const hide = () => {
setShowBottomSheet(false)
}
return (
<SafeAreaView style={styles.safeAreaView}>
<StatusBar barStyle={'dark-content'} />
<View style={styles.container}>
<Pressable
onPress={() => {
setShowBottomSheet(true)
}}
style={styles.showButton}
>
<Text style={styles.buttonText}>Show bottom sheet</Text>
</Pressable>
</View>
<BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}>
<View style={styles.bottomSheetContent}>
<Text style={styles.bottomSheetText}>Hey boys, hey girls!</Text>
<Pressable onPress={hide} style={styles.bottomSheetCloseButton}>
<Text style={styles.buttonText}>X Close</Text>
</Pressable>
</View>
</BottomSheet>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
},
container: {
flex: 1,
},
showButton: {
marginTop: 48,
padding: 16,
backgroundColor: 'mediumspringgreen',
alignSelf: 'center',
borderRadius: 8,
},
buttonText: {
fontSize: 20,
},
bottomSheetContent: {
padding: 40,
alignItems: 'center',
},
bottomSheetText: {
fontSize: 24,
marginBottom: 80,
},
bottomSheetCloseButton: {
padding: 16,
backgroundColor: 'deeppink',
borderRadius: 8,
},
})
export default App
Notes:
I've put an outer semitransparent overlay, but you can get rid of it by deleting it.
I've chosen to close the modal when you click on the outer semitransparent overlay. This is done with the onOuterClick callback, which is optional - don't pass it if you don't want to do anything.
I've put some styling (blue background + border radius) that applies to all bottom sheets, but you can remove it if you want to have different styles.
After a quite long search I found very good library called react-native-swipe-down with MIT licence.
It will help you make a slider <View /> with no effort.
I Hope this library help you out.
import SwipeUpDown from 'react-native-swipe-up-down';
<SwipeUpDown
itemMini={<ItemMini />} // Pass props component when collapsed
itemFull={<ItemFull />} // Pass props component when show full
onShowMini={() => console.log('mini')}
onShowFull={() => console.log('full')}
onMoveDown={() => console.log('down')}
onMoveUp={() => console.log('up')}
disablePressToShow={false} // Press item mini to show full
style={{ backgroundColor: 'green' }} // style for swipe
/>
To achive above type of requirnment we can take help of some greate libraries
1 #gorhom/bottom-sheet
2 react-native-raw-bottom-sheet
But if we want to do with nativelly please find a code below, I'll try to justify the answer:)
For some animation effects I'll take reference from blow site
how-to-create-moving-animations-in-react-native
import React, { useState } from 'react'
import { SafeAreaView, View, ScrollView, Text, Dimensions, TouchableOpacity, Animated } from 'react-native'
const App = () => {
const { height, width } = Dimensions.get('window')
const SCREEN_HEIGHT = Math.round(height)
const SCREEN_WIDTH = Math.round(width)
// Animation
const startValue = new Animated.Value(Math.round(height + height * 0.3))
const endValue = Math.round(height - height * 0.3)
const duration = 1000
const _showBottomView = (key) => {
const toValue = key === 'HIDE' ? height : endValue
Animated.timing(startValue, {
toValue,
duration: duration,
useNativeDriver: true,
}).start()
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.1)' }}>
{/* Header */}
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'black', margin: 5 }}>
<Text>
Header
</Text>
</View>
<View style={{ flex: 9, borderWidth: 1, borderColor: 'black', margin: 5 }}>
<ScrollView
style={{ flex: 1 }}>
{/* Title View */}
<View style={{ height: SCREEN_HEIGHT * 0.1, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<Text>
Content ONE
</Text>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.5, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<Text>
Content TWO
</Text>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.2, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity
activeOpacity={0.85}
onPress={() => _showBottomView()}
style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
<Text>
SHOW BOTTOM VIEW
</Text>
</TouchableOpacity>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.3, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', marginBottom: SCREEN_HEIGHT * 0.01 }}>
<Text>
...REST_CONTENT...
</Text>
</View>
</ScrollView>
</View>
{/* Bottom view */}
<Animated.View
style={[
{
position: 'absolute',
height: height * 0.3,
width: width,
backgroundColor: 'white',
alignItems: 'center', justifyContent: 'center',
borderTopRightRadius: 23, borderTopLeftRadius: 23,
transform: [
{
translateY: startValue
},
],
},
]} >
<TouchableOpacity
activeOpacity={0.85}
onPress={() => _showBottomView('HIDE')}
style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
<Text>
HIDE BOTTOM VIEW
</Text>
</TouchableOpacity>
</Animated.View>
</SafeAreaView>
)
}
export default App
Demo