I have to create Neumorphism styled UI into React Native project and I'm currently developing for android. I've currently encountered a problem in which shadows properties don't work as expected for android. I then tried using react-native-drop-shadow which I read from this blog:
https://blog.logrocket.com/applying-box-shadows-in-react-native/
Here is my current implementation
NeoView.tsx
import React, { ReactNode } from "react";
import { StyleSheet, View, ViewStyle } from "react-native";
import DropShadow from "react-native-drop-shadow";
type NeoViewProps = {
children: ReactNode;
size?: number;
style?: ViewStyle;
};
const NeoView = ({ children, size, style }: NeoViewProps) => {
return (
<>
<DropShadow style={styles.bottomShadow}></DropShadow>
<DropShadow style={styles.topShadow}>
<View
style={[
styles.inner,
{ width: size || 40, height: size || 40, borderRadius: 10 },
style,
]}
>
{children}
</View>
</DropShadow>
</>
);
};
export default NeoView;
const styles = StyleSheet.create({
inner: {
backgroundColor: "#F0F0F3",
alignItems: "center",
justifyContent: "center",
borderColor: "#D3D5D8",
borderWidth: 1,
},
topShadow: {
shadowOffset: {
width: -2,
height: -2,
},
shadowOpacity: 1,
shadowRadius: 4,
shadowColor: "#fff",
},
bottomShadow: {
shadowOffset: {
width: 2,
height: 2,
},
shadowOpacity: 1,
shadowRadius: 4,
shadowColor: "#7A7987",
},
});
Related
I am trying to create a view with a top card showing an image and a bottom card showing relative information in a horizontal flatlist.
The style gets broken on the first load and as soon as I refresh the code without any change, the component shows the correct style as expected.
This is happening after I migrated the react native from 0.60.5 to 0.61.0.
This is the code for component.
<View
accessible={Platform.OS === 'ios' ? false : true}
style={styles.container}>
<View style={styles.itemContainer}>
<View style={styles.topContainer}>
<ImageBackground
source={{uri: item.img, cache: 'default'}}
resizeMode="contain"
imageStyle={{borderRadius: 4}}
style={styles.topContainer}>
</ImageBackground>
<View style={styles.bottomContainer}>
<Text style={styles.destination}>{item.title}</Text>
<Text style={styles.subtitle}>{item.description}</Text>
</View>
</View>
</View>
</View>
This is the stylesheet.
import {StyleSheet, Platform} from 'react-native';
import Color from '../../../../utilities/Color';
import {BaseStyle} from '../../../../utilities/Style';
const flex1 = {
flex: 1,
};
const flexRow = {
flexDirection: 'row',
};
const centerView = {
justifyContent: 'center',
alignItems: 'center',
};
const cardStyle = {
...Platform.select({
ios: {
borderWidth: 1,
borderColor: Color.white,
shadowOffset: {width: 1, height: 1},
shadowOpacity: 0.2,
shadowRadius: 2,
borderRadius: 2,
shadowColor: 'rgba(0, 0, 0, 1.0)',
},
android: {
elevation: 2,
borderRadius: 2,
},
}),
};
export default StyleSheet.create({
container: {
...flex1,
padding: 16,
borderBottomWidth: 1,
borderColor: '#efefef',
},
title: {
...BaseStyle.font16RobotoBoldGray,
},
subtitle: {
...BaseStyle.textSubHead1,
top: 10,
marginRight: 10,
color: Color.lightTextGray,
},
});
export const ItemStyle = StyleSheet.create({
container: {
...flex1,
marginBottom: 15,
},
itemContainer: {
height: 210,
width: 260,
marginRight: 15,
},
topContainer: {
height: 162,
borderRadius: 4,
},
bottomContainer: {
...cardStyle,
position: 'absolute',
left: 0,
right: 0,
top: 120,
marginHorizontal: 8,
paddingHorizontal: 15,
paddingVertical: 12,
borderRadius: 4,
backgroundColor: Color.white,
},
destination: {
...BaseStyle.textTitle,
fontSize: 14,
lineHeight: 18,
color: Color.darkGray,
marginBottom: 8,
},
subHeading: {
marginBottom: 4,
},
caption: {
...BaseStyle.textCaption,
color: Color.lightTextGray,
},
subtitle: {
...BaseStyle.textSubHead1,
},
});
This is the image at the first load
This is the image after I refresh the code.
Please suggest a way, how can I debug it. Or something wrong I am doing in my stylesheet?
Removing all the borderRadius solved it.
I have been trying to get the blur effect to work on Android for a long time.
I tried to solve it using the viewRef reference system but it doesn't work right. Can somebody help me?
The sample page I wrote for Android is as follows;
import React, { useCallback, useEffect, useState, useRef } from 'react';
import { Image, StyleSheet, Text, TouchableOpacity, View, findNodeHandle, InteractionManager } from 'react-native';
import { BlurView } from '#react-native-community/blur';
const AndroidPreviewScreen = ({ route, navigation }) => {
const { speed, brightness, selectedDevice, selectedAnimationId, selectedUserTheme, selectedThemeId, selectedEqAnimation, selectedColors } = route.params;
const selectedAnimation = selectedAnimationId && animationOptions.find(o => o.id === selectedAnimationId);
const selectedTheme = selectedThemeId && themeOptions.find(o => o.id === selectedThemeId);
const [isVisible, setIsVisible] = useState(false);
const [viewRef, setViewRef] = useState(null);
const blurRef = useRef();
useEffect(() => {
setTimeout(() => {
setIsVisible(true);
}, 50);
}, [])
const onBack = useCallback(() => {
setIsVisible(false);
setTimeout(() => {
vibrateLight();
navigation.goBack();
}, 5);
}, []);
return (
<View style={styles.container} >
<TouchableOpacity style={styles.closeBtn} onPress={onBack} hitSlop={hitSlop.mid}>
<FontAwesome5Icon name="times" color={colors.powerCustomBg} size={20} style={styles.closeIcon} />
</TouchableOpacity>
{isVisible && <View style={styles.previewImageContainer}>
{selectedDevice && !selectedDevice.isOn && <View style={styles.offContainer}>
<FontAwesome5Icon name={'info-circle'} size={20} color={colors.powerBtnOn} />
<Text style={styles.offText}>Off</Text>
</View>}
<View style={[styles.colorMaskContainer]}
ref={n => {
if (n && viewRef === null) {
setViewRef(findNodeHandle(n))
}
}}
collapsable={false}
>
// I want to blur this section.
</View>
{console.log("viewRef : : ", viewRef)}
{viewRef && <BlurView
style={styles.blur}
viewRef={viewRef}
blurType={"light"}
blurRadius={20}
blurAmount={20}
downsampleFactor={5}
overlayColor={"light"}
// reducedTransparencyFallbackColor="white"
/>
}
<Image resizeMethod="auto" resizeMode="cover" source={{ uri: 'asset:/images/images/imageMy.webp' }} style={[styles.previewImage]} />
</View>}
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.black,
zIndex: 9999999
},
closeBtn: {
flexDirection: 'row',
position: 'absolute',
right: 15,
top: deviceHeight * 0.13 - 75,
zIndex: 9999,
backgroundColor: colors.noThemeBg,
width: 36,
height: 36,
borderRadius: 20,
alignItems: 'center',
alignContent: 'center',
justifyContent: 'center'
},
closeIcon: {
textAlign: 'center'
},
previewImageContainer: {
flex: 1,
width: '100%',
alignSelf: 'center',
flexDirection: 'column',
overflow: 'hidden',
borderColor: colors.mainBgMid,
},
offContainer: {
position: 'absolute',
top: 20,
flexDirection: 'row',
alignSelf: 'center',
zIndex: 99
},
offText: {
color: colors.powerBtnOn,
fontFamily: 'Montserrat-SemiBold',
fontSize: 14,
lineHeight: 16,
alignSelf: 'center',
marginLeft: 10
},
colorMaskContainer: {
position: 'absolute',
top: '15%',
height: '65%',
width: '100%',
backgroundColor: "#000",
},
colorMask: {
position: 'absolute',
alignSelf: 'center',
width: '100%',
backgroundColor: "#000",
},
blur: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
previewImage: {
position: 'absolute',
height: '100%',
width: '100%',
}
});
export default AndroidPreviewScreen;
I want to blur where I try to refer to viewRef. The reference value I gave in BlurView points to that View.
I am using react-navigation & react-navigation-material-bottom-tabs in react-native to create bottom tab-bar. And I am trying to add shadow effect for bottom tab bar.
My Code for generating shadow is:
const screen1 = createMaterialBottomTabNavigator(
{
Home: HomeScreen,
About: AboutScreen,
Scan: ScanScreen,
Fav: AllScreen
},
{
initialRouteName: "Home",
activeColor: 'red',
inactiveColor: 'blue',
barStyle: {
borderWidth: 0.5,
borderBottomWidth: 1,
backgroundColor: 'white',
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
borderTopColor: '#000',
borderBottomColor: '#000',
borderLeftColor: '#000',
borderRightColor: '#000',
shadowColor: "#000000",
shadowOpacity: 1,
shadowRadius: 30,
shadowOffset: {
height: 10,
width: 10
},
elevation: 5
},
}
);
But shadow effects are not shown in both IOS & Android.
I am a newbie to react-native. I am currently trying to implement the code which can scan and capture image for an ID card. Basically i am able to take image and save to gallery by using react native camera, but i have no idea how to detect the ID card border. I am seeking help which can guide me about the card border detection or some open source library that can implement such function.
Basically, I have already tried to implement react-native-documentscanner-android and rn-doc-scanner-android library. But react-native-documentscanner-android library i failed to implement and the rn-doc-scanner-android is without card border detection function.
Here is my code:
import React, {Component} from 'react';
import { RNCamera } from 'react-native-camera';
import {
StyleSheet,
View,
Text,
TouchableOpacity,
ToastAndroid
} from 'react-native';
import {
Colors
} from 'react-native/Libraries/NewAppScreen';
import Dimensions from 'Dimensions';
import CameraRoll from "#react-native-community/cameraroll";
export default class App extends Component {
constructor(props){
super(props)
}
state = {
barcodes: [],
}
render(){
const { height, width } = Dimensions.get('window');
const maskRowHeight = Math.round((height - 500) / 20);
const maskColWidth = (width - 300) / 2;
return (
<View style={styles.container}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={{
flex: 1,
width: '100%',
justifyContent: "center"
}}
>
<View style={styles.maskOutter}>
<View style={[{ flex: maskRowHeight }, styles.maskRow, styles.maskFrame]} />
<View style={[{ flex: 30 }, styles.maskCenter]}>
<View style={[{ width: maskColWidth }, styles.maskFrame]} />
<View style={styles.maskInner} />
<View style={[{ width: maskColWidth }, styles.maskFrame]} />
</View>
<View style={[{ flex: maskRowHeight }, styles.maskRow, styles.maskFrame]} />
</View>
</RNCamera>
<View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center', backgroundColor: '#2E8B57', margin: 5}}>
<TouchableOpacity onPress={this.takePicture.bind(this)} style={styles.capture}>
<Text style={{ fontSize: 14 }}> SNAP </Text>
</TouchableOpacity>
</View>
</View>
);
}
takePicture = async() => {
if (this.camera) {
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
console.log(data.uri);
ToastAndroid.show(data.uri, ToastAndroid.LONG);
if(data.uri!= null){
console.log('not null')
}else{
console.log('null')
}
CameraRoll.saveToCameraRoll(data.uri);
}
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#2E8B57",
overflow: 'hidden',
//width: 350,
//height: 150,
},
camera: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
maskOutter: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'space-around',
},
maskInner: {
width: 300,
//height: 300,
backgroundColor: 'transparent',
borderColor: '#DC143C',
borderWidth: 1,
},
maskFrame: {
backgroundColor: 'rgba(1,1,1,0.6)',
},
maskRow: {
width: '100%',
},
maskCenter: { flexDirection: 'row' },
});
I'm trying to add a shadow on the bottom of a view, but I don't how to do it on Android. With elevation it put a shadow also on the top. Is there a way to do it like on iOS?
Here's my code:
export function makeElevation(elevation) {
const iosShadowElevation = {
shadowOpacity: 0.0015 * elevation + 0.18,
shadowRadius: 0.5 * elevation,
shadowOffset: {
height: 0.6 * elevation,
},
};
const androidShadowElevation = {
elevation,
};
return Platform.OS === 'ios' ? iosShadowElevation : androidShadowElevation;
}
left: iOS (expected)
right: Android
EDIT: The only "fake" solution I found is to use react-native-linear-gradient instead to create a custom shadow.
You can use overflow: 'hidden' to achieve the desired result without having to install a library.
wrap the view in a parent view and set the parent's overflow to hidden and apply a padding only on the side where you want your shadow to appear like so:
<View style={{ overflow: 'hidden', paddingBottom: 5 }}>
<View
style={{
backgroundColor: '#fff',
width: 300,
height: 60,
shadowColor: '#000',
shadowOffset: { width: 1, height: 1 },
shadowOpacity: 0.4,
shadowRadius: 3,
elevation: 5,
}}
/>
</View>
result:
here's a custom component that you can use:
import React from 'react'
import { View, StyleSheet, ViewPropTypes } from 'react-native'
import PropTypes from 'prop-types'
const SingleSidedShadowBox = ({ children, style }) => (
<View style={[ styles.container, style ]}>
{ children }
</View>
);
const styles = StyleSheet.create({
container:{
overflow: 'hidden',
paddingBottom: 5,
}
});
SingleSidedShadowBox.propTypes = {
children: PropTypes.element,
style: ViewPropTypes.style,
};
export default SingleSidedShadowBox;
example:
<SingleSidedShadowBox style={{width: '90%', height: 40}}>
<View style={{
backgroundColor: '#fff',
width: '100%',
height: '100%',
shadowColor: '#000',
shadowOffset: { width: 1, height: 1 },
shadowOpacity: 0.4,
shadowRadius: 3,
elevation: 5,
}} />
</SingleSidedShadowBox>
you can adjust the padding depending on your shadow
Unfortunately RN don't support it by default, check blow link
https://ethercreative.github.io/react-native-shadow-generator/
but you can use npm packages like this
Answers above are quite helpful but the workaround that worked best for me is by wrapping both, 1-The component dropping the shadow and 2-The component the shadow is being dropped on in a component with the style rule overflow: "hidden"
Example:
function SomeScreen (){
return (
<View style={{overflow: "hidden"}}/*Top shadow is hidden*/>
<NavBar style={styles.shadow}/*The component dropping a shadow*/ />
<ProductList /*The component under the shadow*/ />
</View>
);
}
const styles = StyleSheet.create({
shadow: {
shadowColor: "black",
shadowOffset: { width: 0, height: 4 },
shadowRadius: 6,
shadowOpacity: 0.2,
elevation: 3,
}
});
Just append/put this to main view container:
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: {width: 1, height: 3},
shadowOpacity: 0.4,
},
android: {
elevation: 4,
},
}),
},
});