Related
I have a project, just user tap in the button and it started recording. If user haven't speak, it stops, and if user tap at the same button, record stopped. Now it can storage in local path, but i hope in the futere i will requests this files in the server
The code:
import { StyleSheet, Text, View, Image, Pressable } from 'react-native'
import React from 'react'
import { useAuth } from '../AuthContext'
import { COLORS } from '../assets/colors/colors';
import Train_word from '../assets/images/Train_word.svg'
import Train_word_2 from '../assets/images/Train_word_2.svg'
const Train = () => {
const [user] = useAuth()
return (
<View style={styles.container}>
<View style={styles.header}>
<Image
source={require('../assets/images/Logo_small.png')}
style={styles.logo_s}
resizeMode='contain'/>
</View>
<View style={styles.main_cont}>
<Train_word marginBottom={34}/>
<Train_word_2 marginBottom={55}/>
<Pressable marginBottom={180}>
<Image
source={require('../assets/images/Start_img.png')}
style={styles.start_img}>
</Image>
</Pressable>
<Pressable style={styles.result}>
<Text style={styles.text_result}>Получить результат</Text>
</Pressable>
</View>
<Image
source={require('../assets/images/bottom_menu.png')}
style={styles.img_bg}/>
</View>
)
}
export default Train
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "rgba(243, 239, 239, 1)",
alignItems: 'center'
},
img_bg: {
width: 412,
height: 80,
},
logo_s: {
width: 100,
height: 100,
left: 150,
top: -130,
},
header: {
backgroundColor: 'transeparent',
flexDirection: 'row',
alignItems:'center',
height: 100,
paddingTop: 180,
paddingRight: 35
},
main_cont: {
alignItems: 'center',
top: -90,
flex: 1,
},
start_img: {
width: 286,
height: 286,
},
result: {
backgroundColor: 'transeparent',
width: 178,
height: 25,
alignItems: "center",
left: -63,
},
text_result: {
fontFamily: 'OpenSans-Italic',
color: COLORS.text,
fontSize: 16,
textDecorationLine: 'underline'
}
})
Thanks for everyone, i'm beginner in react native
I am trying to create a custom React Component: A "Card" with styling that makes it look like a gray rectangle with text inside of it.
I'll attach the files, but the simulator screen is white and it doesn't show the Background Image with the Card with the Text. If I get rid of the "default" word in the Card component, then it just shows the gray card but still no background image.
Any ideas? Thanks!
That's App.js
import React from 'react';
import { Image, SafeAreaView, StyleSheet, Text, View} from 'react-native';
import { ImageBackground, Dimensions } from 'react-native';
import {Card} from './Components/Card'
const deviceWidth = Dimensions.get('window').width
export default function App() {
return (
<View>
<ImageBackground style={{flex: 1}} source={require("./assets/gradient_dark_orange_navy.png")}>
<Card title='MY TITLE!'></Card>
</ImageBackground>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f4ae74',
alignItems: 'center',
justifyContent: 'center',
},
smallImage: {
width: 50,
height: 50
},
mediumImage: {
width: 150,
height: 150
},
container: {
flex: 1,
backgroundColor: '#f4ae74',
justifyContent: 'center',
},
bar: {
position: 'absolute',
bottom: 0,
width: "100%",
height: "10%",
backgroundColor: '#FFC107',
borderRadius: 9,
},
card: {
width: deviceWidth - 32,
marginHorizontal: 16,
backgroundColor: 'lightgray',
height: deviceWidth * 1,
borderRadius: 35,
},
shadowProp: {
shadowRadius: 12,
shadowOpacity: 0.8,
shadowColor: "#757575",
shadowOffset: {
width: 0,
height: 3,
}
},
openingCardStyle:{
bottom: 65,
position: 'absolute',
height: 550
}
});
Then this is Card.js
import React from 'react';
import { Image, SafeAreaView, StyleSheet, Text, View} from 'react-native';
import { ImageBackground, Dimensions } from 'react-native';
const deviceWidth = Dimensions.get('window').width
export function Card (props) {
return (
<View style={[styles.card, styles.shadowProp, styles.openingCardStyle]}>
<Text style={{align: 'center'}}>
{props.title}
{props.subtitle}
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f4ae74',
alignItems: 'center',
justifyContent: 'center',
},
smallImage: {
width: 50,
height: 50
},
mediumImage: {
width: 150,
height: 150
},
container: {
flex: 1,
backgroundColor: '#f4ae74',
justifyContent: 'center',
},
bar: {
position: 'absolute',
bottom: 0,
width: "100%",
height: "10%",
backgroundColor: '#FFC107',
borderRadius: 9,
},
card: {
width: deviceWidth - 32,
marginHorizontal: 16,
backgroundColor: 'lightgray',
height: deviceWidth * 1,
borderRadius: 35,
},
shadowProp: {
shadowRadius: 12,
shadowOpacity: 0.8,
shadowColor: "#757575",
shadowOffset: {
width: 0,
height: 3,
}
},
openingCardStyle:{
bottom: 65,
position: 'absolute',
height: 550
}
})
It could be your image link require("./assets/gradient_dark_orange_navy.png") is not correct so it does not show the image, try ramdon image to see if it work source={uri: "https://reactjs.org/logo-og.png"}
The problem is in your card styling(styles.card) inside Card.js file, You have given backgroundColor property inside styles.card object which is overriding your ImageBackground.
Just remove backgroundColor property from styles.card
card: {
width: deviceWidth - 32,
marginHorizontal: 16,
height: deviceWidth * 1,
borderRadius: 35,
},
How can I achieve this in react native?
So far I have this and I want to implement the middle curve. I don't know to either handle it with a transparent view or switch to SVG completely
and this the tabBar component
/* eslint-disable react/prop-types */
import React, { Component } from 'react'
import { TouchableOpacity, Text, StyleSheet, View } from 'react-native'
import { Colors } from 'App/Theme'
export default class TabBar extends Component {
render() {
let {
renderIcon,
getLabelText,
activeTintColor,
inactiveTintColor,
onTabPress,
onTabLongPress,
getAccessibilityLabel,
navigation,
showLabel,
} = this.props
let { routes, index: activeRouteIndex } = navigation.state
return (
<View style={styles.tabBar}>
{routes.map((route, routeIndex) => {
let isRouteActive = routeIndex === activeRouteIndex
let tintColor = isRouteActive ? activeTintColor : inactiveTintColor
return (
<TouchableOpacity
key={routeIndex}
style={styles.tab}
onPress={() => {
onTabPress({ route })
}}
onLongPress={() => {
onTabLongPress({ route })
}}
accessibilityLabel={getAccessibilityLabel({ route })}
>
{renderIcon({ route, focused: isRouteActive, tintColor })}
{showLabel ? <Text>{getLabelText({ route })}</Text> : null}
</TouchableOpacity>
)
})}
</View>
)
}
}
const styles = StyleSheet.create({
tab: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
tabBar: {
alignSelf: 'center',
backgroundColor: Colors.primary,
borderRadius: 50,
bottom: 10,
elevation: 2,
flexDirection: 'row',
height: 65,
position: 'absolute',
width: '95%',
},
infinity: {
width: 80,
height: 100,
},
infinityBefore: {
position: 'absolute',
top: 0,
left: 0,
width: 0,
height: 0,
borderWidth: 20,
borderColor: 'red',
borderStyle: 'solid',
borderTopLeftRadius: 50,
borderTopRightRadius: 50,
borderBottomRightRadius: 50,
borderBottomLeftRadius: 0,
transform: [{ rotate: '-135deg' }],
},
infinityAfter: {
position: 'absolute',
top: 0,
right: 0,
width: 0,
height: 0,
borderWidth: 20,
borderColor: 'red',
borderStyle: 'solid',
borderTopLeftRadius: 50,
borderTopRightRadius: 0,
borderBottomRightRadius: 50,
borderBottomLeftRadius: 50,
transform: [{ rotate: '-135deg' }],
},
})
here is a demo: https://snack.expo.io/#nomi9995/cf371e
you need to use react-native-svg
yarn add react-native-svg
import React, { Component } from "react";
import {
Text,
StyleSheet,
View,
Dimensions,
TouchableHighlight,
} from "react-native";
import Svg, { Circle, Path } from "react-native-svg";
const tabs = [1, 2, 3, 4, 5];
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
pathX: "357",
pathY: "675",
pathA: "689",
pathB: "706",
};
}
render() {
return (
<View style={[styles.container]}>
<View style={[styles.content]}>
<View style={styles.subContent}>
{tabs.map((_tabs, i) => {
return (
<TouchableHighlight
key={i}
underlayColor={"transparent"}
onPress={() => console.log("onPress")}
>
<View>
</View>
</TouchableHighlight>
);
})}
</View>
<Svg
version="1.1"
id="bottom-bar"
x="0px"
y="0px"
width="100%"
height="100"
viewBox="0 0 1092 260"
space="preserve"
>
<Path
fill={"#373A50"}
stroke={"#373A50"}
d={`M30,60h${this.state.pathX}.3c17.2,0,31,14.4,30,31.6c-0.2,2.7-0.3,5.5-0.3,8.2c0,71.2,58.1,129.6,129.4,130c72.1,0.3,130.6-58,130.6-130c0-2.7-0.1-5.4-0.2-8.1C${this.state.pathY}.7,74.5,${this.state.pathA}.5,60,${this.state.pathB}.7,60H1062c16.6,0,30,13.4,30,30v94c0,42-34,76-76,76H76c-42,0-76-34-76-76V90C0,73.4,13.4,60,30,60z`}
/>
<Circle
fill={"#7EE6D2"}
stroke={"#7EE6D2"}
cx="546"
cy="100"
r="100"
/>
</Svg>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
overflow: "hidden",
},
content: {
flexDirection: "column",
zIndex: 0,
width: Dimensions.get("window").width - 30,
marginBottom: "4%",
left: "4%",
right: "4%",
position: "absolute",
bottom: "1%",
},
subContent: {
flexDirection: "row",
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
zIndex: 1,
position: "absolute",
bottom: 5,
}
});
i hope this will help you.
Here is 2 solution according to your requirement.
If you want this type of design without selection then this code will help you :
https://github.com/alex-melnyk/clipped-tabbar
And if you need on each tab selection then here is other easy library for you :
https://github.com/Jm-Zion/rn-wave-bottom-bar
It's not obvious that this can be done with only <View/> components. I would split the TabBar into a flex row container with three subviews, and create an SVG with the filled inverted radius to be used in the center subview. To render the SVG, use react-native-svg. See a rough layout below:
...
import { SvgXml } from 'react-native-svg';
import TabCenterSvg from ‘assets/my-svg.svg’
export default class TabBar extends Component {
render() {
return (
<View style={styles.tabBar}>
<View style={styles.leftContainer}>
{/* Left Buttons */}
</View>
<View style={styles.centerContainer}>
<View style={styles.centerInnerTopContainer}>
{/* Add Button */}
</View>
<View style={styles.centerInnerBottomContainer}>
<SvgXml xml={TabCenterSvg} />
</View>
</View>
<View style={styles.rightContainer}>
{/* Right Icons */}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
tabBar: {
alignSelf: 'center',
borderRadius: 50,
bottom: 10,
elevation: 2,
flexDirection: 'row',
height: 65,
position: 'absolute',
width: '95%',
},
leftContainer: {
flex: 1,
flexDirection: 'row',
borderBottomLeftRadius: 50,
borderTopLeftRadius: 50,
borderTopRightRadius: 50,
backgroundColor: Colors.primary,
},
centerContainer: {
flex: 1,
flexDirection: 'column',
},
centerInnerTopContainer: {
flex: 1,
},
centerInnerBottomContainer: {
flex: 1,
},
rightContainer: {
flex: 1,
flexDirection: 'row',
borderTopLeftRadius: 50,
borderTopRightRadius: 50,
borderBottomRightRadius: 50,
backgroundColor: Colors.primary,
},
})
Use this library's code and customize according to your UI
https://www.npmjs.com/package/curved-bottom-navigation-bar
Note: I'll not recommend this library as there are low weekly downloads.
Rather than using the whole library, you can use its code.
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
How do I render a shadow on a View? I've tried many combinations of shadowColor, shadowOffset, shadowOpacity, and shadowRadius, which seem to do nothing. I am sure the style is applied correctly, since other attributes I've set work.
I am using React-Native 0.40 and below code works for me both on IOS and Android.
(Android-only) Sets the elevation of a view, using Android's underlying elevation API. This adds a drop shadow to the item and affects z-order for overlapping views. Only supported on Android 5.0+, has no effect on earlier versions.
class MainApp extends Component {
render() {
return (
<View style={styles.container}>
<View elevation={5} style={styles.buttonContainer}>
<Text style={styles.textStyle}>Shadow Applied</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF'
},
textStyle: {
color: '#FFFFFF'
},
buttonContainer: {
backgroundColor: '#2E9298',
borderRadius: 10,
padding: 10,
shadowColor: '#000000',
shadowOffset: {
width: 0,
height: 3
},
shadowRadius: 5,
shadowOpacity: 1.0
}
})
Tested on iPhone.
Edit
Comment from # James. Thanks.
Note: For those on android, the backgroundColor is critical. I was using View as a container for another element and couldn't get a shadow until I specified a background color.
Use elevation to implement shadows on RN Android. Added elevation prop #27
<View elevation={5}>
</View>
It appears to be a bug in React native that shadowOpacity is set to type CGFloat instead of float according to CALayer doc. use iPhone 5 simulator before it's fixed. (CGFloat is float in older devices. )
The React Native issue which is tracking this is:
https://github.com/facebook/react-native/issues/449
viewStyle : {
backgroundColor: '#F8F8F8',
justifyContent: 'center',
alignItems: 'center',
height: 60,
paddingTop: 15,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
marginBottom: 10,
elevation: 2,
position: 'relative'
},
Use marginBottom: 10
You have to give elevation prop to View
<View elevation={5} style={styles.container}>
<Text>Hello World !</Text>
</View>
styles can be added like this:
const styles = StyleSheet.create({
container:{
padding:20,
backgroundColor:'#d9d9d9',
shadowColor: "#000000",
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 1
}
},
})
panel: {
// ios
backgroundColor: '#03A9F4',
alignItems: 'center',
shadowOffset: {width: 0, height: 13},
shadowOpacity: 0.3,
shadowRadius: 6,
// android (Android +5.0)
elevation: 3,
}
or you can use react-native-shadow for android
All About margins
this works in Android, but did not test it in ios
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { View, Platform } from 'react-native'
import EStyleSheet from 'react-native-extended-stylesheet'
const styles = EStyleSheet.create({
wrapper: {
margin: '-1.4rem'
},
shadow: {
padding: '1.4rem',
margin: '1.4rem',
borderRadius: 4,
borderWidth: 0,
borderColor: 'transparent',
...Platform.select({
ios: {
shadowColor: 'rgba(0,0,0, 0.4)',
shadowOffset: { height: 1, width: 1 },
shadowOpacity: 0.7,
shadowRadius: '1.4rem'
},
android: {
elevation: '1.4rem'
}
})
},
container: {
padding: 10,
margin: '-1.4rem',
borderRadius: 4,
borderWidth: 0,
borderColor: '#Fff',
backgroundColor: '#fff'
}
})
class ShadowWrapper extends PureComponent {
static propTypes = {
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.node,
PropTypes.arrayOf(PropTypes.element)
]).isRequired
}
render () {
return (
View style={styles.wrapper}
View style={styles.shadow}
View style={styles.container}
{this.props.children}
View
View
View
)
}
}
export default ShadowWrapper
by styled component
const StyledView = styled.View`
border-width: 1;
border-radius: 2;
border-color: #ddd;
border-bottom-width: 0;
shadow-color: #000;
shadow-offset: {width: 0, height: 2};
shadow-opacity: 0.8;
shadow-radius: 2;
elevation: 1;
`
or by styles
const styles = StyleSheet.create({
containerStyle: {
borderWidth: 1,
borderRadius: 2,
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10,
}
})
I'm using Styled Components and created a helper function for myself.
It takes the given Android elevation and creates a fairly equivalent iOS shadow.
stylingTools.js
import { css } from 'styled-components/native';
/*
REMINDER!!!!!!!!!!!!!
Shadows do not show up on iOS if `overflow: hidden` is used.
https://react-native.canny.io/feature-requests/p/shadow-does-not-appear-if-overflow-hidden-is-set-on-ios
*/
// eslint-disable-next-line import/prefer-default-export
export const crossPlatformElevation = (elevation: number = 0) => css`
/* Android - native default is 4, we're setting to 0 to match iOS. */
elevation: ${elevation};
/* iOS - default is no shadow. Only add if above zero */
${elevation > 0
&& css`
shadow-color: black;
shadow-offset: 0px ${0.5 * elevation}px;
shadow-opacity: 0.3;
shadow-radius: ${0.8 * elevation}px;
`}
`;
To use
import styled from 'styled-components/native';
import { crossPlatformElevation } from "../../lib/stylingTools";
export const ContentContainer = styled.View`
background: white;
${crossPlatformElevation(10)};
`;