Related
I have used the below model to make a handler rotate but cannot find a way to manipulate it as to make the handle rotate from where it begins instead of its center. As well, I am struggling to make the rotation occur with only one finger instead of two.
I think maybe the answer lies in the withAnchorPoint library but Iām not sure of how to apply it.
Requiring assistance šš¾
import React from 'react';
import {Animated, StatusBar, Image, ImageBackground, Dimensions, StyleSheet, View, Text} from "react-native";
import { PanGestureHandler, PinchGestureHandler, State, RotationGestureHandler } from 'react-native-gesture-handler';
//import { withAnchorPoint } from 'react-native-anchor-point';
import { USE_NATIVE_DRIVER } from '../../config';
const {width} = Dimensions.get('screen');
const SIZE = width * .9;
export default class MovableClock extends React.Component {
panRef = React.createRef();
rotationRef = React.createRef();
pinchRef = React.createRef();
constructor(props) {
super(props);
/* Pinching */
this._baseScale = new Animated.Value(1);
this._pinchScale = new Animated.Value(1);
this._scale = Animated.multiply(this._baseScale, this._pinchScale);
this._lastScale = 1;
this._onPinchGestureEvent = Animated.event(
[{ nativeEvent: { scale: this._pinchScale } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
/* Rotation */
this._rotate = new Animated.Value(0);
this._rotateStr = this._rotate.interpolate({
inputRange: [-100, 100],
outputRange: ['-100rad', '100rad'],
});
this._lastRotate = 0;
this._onRotateGestureEvent = Animated.event(
[{ nativeEvent: { rotation: this._rotate } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
/* Tilt */
this._tilt = new Animated.Value(0);
this._tiltStr = this._tilt.interpolate({
inputRange: [-501, -500, 0, 1],
outputRange: ['1rad', '1rad', '0rad', '0rad'],
});
this._lastTilt = 0;
this._onTiltGestureEvent = Animated.event(
[{ nativeEvent: { translationY: this._tilt } }],
{ useNativeDriver: USE_NATIVE_DRIVER }
);
}
_onRotateHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this._lastRotate += event.nativeEvent.rotation;
this._rotate.setOffset(this._lastRotate);
this._rotate.setValue(0);
}
};
_onPinchHandlerStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this._lastScale *= event.nativeEvent.scale;
this._baseScale.setValue(this._lastScale);
this._pinchScale.setValue(1);
}
};
_onTiltGestureStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this._lastTilt += event.nativeEvent.translationY;
this._tilt.setOffset(this._lastTilt);
this._tilt.setValue(0);
}
};
render() {
return (
<View style={styles.background}>
<StatusBar hidden={true}/>
<View style={[styles.bigQuadran]}>
</View>
<Image style={styles.numbers}
source={require("../assets/nobgfreeclock2.png")}/>
<View style={[styles.mediumQuadran]}/>
<PanGestureHandler
ref={this.panRef}
onGestureEvent={this._onTiltGestureEvent}
onHandlerStateChange={this._onTiltGestureStateChange}
minDist={10}
minPointers={2}
maxPointers={2}
avgTouches>
<Animated.View style={[styles.mover
//{transform: [{ translateX: this.translateX, }, { translateY: this.translateY}]}
]}>
<RotationGestureHandler
ref={this.rotationRef}
simultaneousHandlers={this.pinchRef}
onGestureEvent={this._onRotateGestureEvent}
onHandlerStateChange={this._onRotateHandlerStateChange}
>
<Animated.View style={[styles.mover]}>
<PinchGestureHandler
ref={this.pinchRef}
simultaneousHandlers={this.rotationRef}
onGestureEvent={this._onPinchGestureEvent}
onHandlerStateChange={this._onPinchHandlerStateChange}
>
<Animated.View style={[styles.hours,
{transform: [
{ perspective: 200 },
{ scale: this._scale },
{ rotate: this._rotateStr },
{ rotateX: this._tiltStr },
]},
]}/>
</PinchGestureHandler>
</Animated.View>
</RotationGestureHandler>
</Animated.View>
</PanGestureHandler>
{/*
<PanGestureHandler onGestureEvent={this.onPanGestureEvent}>
<Animated.View style={[styles.mover, {
transform: [{ translateX: this.translateX, }, { translateY: this.translateY}]}]}>
<View style={styles.minutes}/>
</Animated.View>
</PanGestureHandler>
<PanGestureHandler onGestureEvent={this.onPanGestureEvent}>
<Animated.View style={[styles.mover, {
transform: [{ translateX: this.translateX, }, { translateY: this.translateY}]}]}>
<View style={styles.seconds}/>
</Animated.View>
</PanGestureHandler>
*/}
<View style={[styles.smallQuadran]}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'whitesmoke',
alignItems: 'center',
justifyContent: 'center',
},
background: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'transparent'
},
mover: {
position: 'absolute',
width: SIZE,
height: SIZE,
borderRadius: SIZE/2,
alignItems: 'center',
justifyContent: 'flex-start',
top: 68
},
hours: {
backgroundColor: 'black',
height: '20%',
marginTop: '30%',
width: 4.5,
borderRadius: 4.5
},
minutes: {
backgroundColor: 'black',
height: '35%',
marginTop: '15%',
width: 3.5,
borderRadius: 3.5
},
seconds: {
backgroundColor: 'rgba(227, 71, 134, 1)',
height: '35%',
marginTop: '15%',
width: 2,
borderRadius: 2
},
bigQuadran: {
width: SIZE * 0.815,
height: SIZE * 0.815,
borderRadius: SIZE * 0.40,
backgroundColor: 'ghostwhite',
borderColor: 'black',
borderWidth: SIZE * 0.030,
position: 'absolute',
top: 100
},
smallQuadran: {
width: 10,
height: 10,
borderRadius: 5,
position: 'absolute',
backgroundColor: 'rgba(227, 71, 134, 1)',
top: 250
},
numbers: {
width: SIZE * 0.78,
height: SIZE * 0.78,
position: 'absolute',
top: 107,
borderRadius: SIZE * 4
}
})
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,
},
I've got a button like this (material-ui):
//theme.js
export const XButtonTop = withStyles({
root: {
borderColor: medium_col,
borderRadius: 1,
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
height: 28
},
label: {
textTransform: "uppercase",
fontSize: "10px"
}
})(Button);
//App.js
import {
XButtonTop
} from "../theme";
const Selector = state => {
return (
<div>
<XButtonTop fullWidth size="small" disableElevation>
)
</XButtonTop>
</div>
)
}
I need to rotate the label (90 degrees).
Can someone help me please? Thanks
label: {
textTransform: 'capitalize',
transform: 'rotate(-90deg)',
}
Then you may want to change the height of the button too. Something like this for the root:
height: 120,
width: 30
I've found this weird behavior in IOS (both on the simulator and on a real device, but I only have screenshots from the simulator) where on input to the TextInput component, it puts a weird highlight behind the text you input. I've referenced this (since closed) issue: https://github.com/facebook/react-native/issues/7070
And I've scoured the docs (https://facebook.github.io/react-native/docs/textinput) for an answer to this, but can't quite seem to come up with any answers. I thought I was close with the selectTextOnFocus prop, but I set that to false and nothing changed (the behavior remained).
I have also tried setting textDecorationColor and textShadowColor to transparent, to no avail. I am really at a loss of what to do right now.
Here is the code I have for the input:
import React from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
export class GeneralInput extends React.Component {
constructor(props) {
super(props);
this.state = {
placeholder: this.props.placeholder,
inputValue: "",
inputting: false,
};
}
whenInputIsFocused() {
this.setState({placeholder: ""});
}
whenInputIsBlurred() {
if (this.state.inputValue === "") {
this.setState({placeholder: this.props.placeholder});
}
}
focusNextField(nextField) { this.refs[nextField].focus(); }
render() {
const autoFocus = this.props.autoFocus == 'true';
const multiline = this.props.multiline == 'true';
return(
<View style={styles.outerContainer}>
<Text style={styles.labelText}>{this.props.labelText}</Text>
<TextInput
autoCapitalize='none'
autoFocus={autoFocus}
onChangeText={(inputValue) => this.setState({inputValue})}
value={this.state.inputValue}
secureTextEntry={this.props.secureTextEntry}
onBlur={this.whenInputIsBlurred.bind(this)}
onFocus={this.whenInputIsFocused.bind(this)}
underlineColorAndroid="transparent"
keyboardType={this.props.type}
returnKeyType={this.props.returnKeyType}
placeholder={this.state.placeholder}
placeholderTextColor='rgba(255, 255, 255, 0.3)'
multiline={multiline}
selectTextOnFocus={false}
onSubmitEditing={() => {this.focusNextField(this.props.ref)}}
blurOnSubmit={(this.props.moveAlongType === 'next') ? false : true}
style={styles.inputStyles} />
</View>
);
}
}
const styles = StyleSheet.create({
outerContainer: {
justifyContent: 'center',
alignItems: 'flex-start',
width: '90%',
marginBottom: 20,
},
labelText: {
fontFamily: 'rubik-bold',
fontSize: 14,
fontWeight: 'bold',
color: '#fff',
marginBottom: 5,
},
inputStyles: {
height: 40,
borderRadius: 2,
backgroundColor: 'rgba(255, 255, 255, 0.3);',
shadowColor: 'rgba(0, 0, 0, 0.15)',
shadowOffset: {width: 0,height: 2},
shadowOpacity: 0,
shadowRadius: 0,
width: '100%',
textDecorationColor: 'transparent',
fontSize: 14,
color: '#fff',
paddingLeft: 15,
fontFamily: 'rubik-bold',
},
});
And here are the screenshots of what is actually happening (the first screenshot is with the highlight, the second is just the input with the placeholder text for reference):
So the question is...how do I make that weird highlight go away on ios?
Text is not getting selected, it is just the background color you have given in the style.
Just remove the background color from the style of the <TextInput />
So, as per #Siraj the reason this odd behavior was happening was because the background color I had applied to the <TextInput /> component was also being applied to the text being inputed. So, I wrapped the <TextInput /> in a <View />, applied the height, width, backgroundColor, shadow, and borderRadius props to the surrounding <View />, and it has the desired effect! See the code below:
import React from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
export class GeneralInput extends React.Component {
constructor(props) {
super(props);
this.state = {
placeholder: this.props.placeholder,
inputValue: "",
inputting: false,
};
}
whenInputIsFocused() {
this.setState({placeholder: ""});
}
whenInputIsBlurred() {
if (this.state.inputValue === "") {
this.setState({placeholder: this.props.placeholder});
}
}
focusNextField(nextField) { this.refs[nextField].focus(); }
render() {
const autoFocus = this.props.autoFocus == 'true';
const multiline = this.props.multiline == 'true';
return(
<View style={styles.outerContainer}>
<Text style={styles.labelText}>{this.props.labelText}</Text>
<View style={styles.inputContainer}> // added View
<TextInput
autoCapitalize='none'
autoFocus={autoFocus}
onChangeText={(inputValue) => this.setState({inputValue})}
value={this.state.inputValue}
secureTextEntry={this.props.secureTextEntry}
onBlur={this.whenInputIsBlurred.bind(this)}
onFocus={this.whenInputIsFocused.bind(this)}
underlineColorAndroid="transparent"
keyboardType={this.props.type}
returnKeyType={this.props.returnKeyType}
placeholder={this.state.placeholder}
placeholderTextColor='rgba(255, 255, 255, 0.3)'
multiline={multiline}
selectTextOnFocus={false}
onSubmitEditing={() => {this.focusNextField(this.props.ref)}}
blurOnSubmit={(this.props.moveAlongType === 'next') ? false : true}
style={styles.inputStyles} />
</View> // Closing the added View
</View>
);
}
}
const styles = StyleSheet.create({
outerContainer: {
justifyContent: 'center',
alignItems: 'flex-start',
width: '90%',
marginBottom: 20,
},
labelText: {
fontFamily: 'rubik-bold',
fontSize: 14,
fontWeight: 'bold',
color: '#fff',
marginBottom: 5,
},
inputContainer: { // added styles
height: 40,
width: '100%',
backgroundColor: 'rgba(255, 255, 255, 0.3);',
shadowColor: 'rgba(0, 0, 0, 0.15)',
shadowOffset: {width: 0,height: 2},
shadowOpacity: 0,
shadowRadius: 0,
borderRadius: 2,
},
inputStyles: {
height: '100%',
width: '100%',
fontSize: 14,
color: '#fff',
paddingLeft: 15,
fontFamily: 'rubik-bold',
},
});
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)};
`;