I am trying to use a React Native Animation to remove a padding(by making it 0) and then to put it back.
The following code is managing the animations:
componentWillMount() {
this.animatedValueLateralPadding = new Animated.Value(Constants.LIST_ITEM_MARGIN * this.props.dimensions.windowWidth);
}
componentWillReceiveProps(nextProps) {
if(nextProps.index == this.props.element.ordinalNumber) {
Animated.stagger(Constants.RESIZED_TIME, [
Animated.parallel([
Animated.timing(this.animatedValueLateralPadding, {
toValue: 0,
duration: Constants.RESIZE_TRANSITION_TIME
}),
]),
Animated.parallel([
Animated.timing(this.animatedValueLateralPadding, {
toValue: Constants.LIST_ITEM_MARGIN * nextProps.dimensions.windowWidth,
duration: Constants.RESIZE_TRANSITION_TIME
}),
])
]).start();
}
}
In my render method I specify the style like this:
const animatedStyle = {paddingLeft: this.animatedValueLateralPadding, paddingRight: this.animatedValueLateralPadding};
And then animatedStyle is used in this component which is returned:
<ScrollView
contentContainerStyle={[listStyles.container, animatedStyle]}
>
//some other code
The rest of the style is this:
const listStyles = StyleSheet.create({
container: {
backgroundColor: Constants.COLOR_BLACK,
minHeight: '100%'
}
});
The problem is that the padding does not disappear and I am getting this warning:
Failed prop type:Invalid prop 'paddingLeft' supplied to 'ScrollView'. Bad object:
{
"backgroundColor": "#000000",
"minHeight": "100%",
"paddingLeft": 18,
"paddingRight": 18
}
I don't understand why it doesn't like how I specified paddingLeft.
I tried to pass a String instead of Int all to the Animated.Value object:
this.animatedValueLateralPadding = new Animated.Value(String.valueOf(Constants.LIST_ITEM_MARGIN * this.props.dimensions.windowWidth));
and
toValue: String.valueOf(0),
and
toValue: String.valueOf(Constants.LIST_ITEM_MARGIN * nextProps.dimensions.windowWidth)
However, I am getting:
Error while updating property: 'paddingLeft' in shadow node of type: RCTView
null
Unknown value: function String() {
[native code]
}0
So why does it have a problem with the way in which I specify the padding? Any idea how this can be fixed?
You need to use Animated components like Animated.View, Animated.Text to have this animation.
Consider reading this: https://facebook.github.io/react-native/docs/animations.html
Just change your ScrollView to Animated.ScrollView
Related
I have a problem cause I don’t know how it works.
I’ve created a scene where you can choose an upgrade for your character.
I have 3 upgrades you can choose from.
So I’m creating a class for each upgrade, I wanted to import them into the upgradeScene (UI).
I’ve tried this… but I can’t see anything with no errors in the console.
increase_speed.js
let rectC;
let cardC; //container
let increase_speed_title;
let increase_speed_description;
let increase_speed_btn;
export default class IncreaseSpeed extends Phaser.Scene {
constructor() {
super('increase_speed');
}
preload() {
this.load.image('cardbg', './Assets/UI/cardbg.png');
}
create() {
const screenCenterX = this.cameras.main.worldView.x + this.cameras.main.width / 2;
const screenCenterY = this.cameras.main.worldView.y + this.cameras.main.height / 2;
rectC = this.add.image(0, 0, 'cardbg');
increase_speed_title = this.add.text(-65, -100, 'Increase\nSpeed', {
fontFamily: 'dogicaPixel',
fontSize: '20px',
align: 'center'
});
increase_speed_description = this.add.text(-80, 0, 'Lorem ipsum\ndolor sit amet', {
fontFamily: 'dogicaPixel',
fontSize: '15px',
align: 'center'
});
increase_speed_btn = this.add.text(-65, 120, 'UPGRADE', {
fontFamily: 'dogicaPixel',
fontSize: '20px',
align: 'center'
});
cardC = this.add.container(screenCenterX, screenCenterY, [rectC, increase_speed_title, increase_speed_description, increase_speed_btn]);
}
}
upgradeScene.js in the create() function:
const increase_speed = new IncreaseSpeed(this, 300, 400);
this.add.existing(increase_speed);
I’m not sure if this is correct export default class IncreaseSpeed extends Phaser.Scene cause maybe should be a game object. But I have no idea how to do that.
If you are adding a scene (want it should stay a scene, and not use a different gameobject), you can simply call the function this.scene.add(...):
this.scene.add(this, IncreaseSpeed, true);
instead of calling:
const increase_speed = new IncreaseSpeed(this, 300, 400);
this.add.existing(increase_speed);
and the Scene should be displayed, as an overlay.
Here is a link to the documentation of this function.
There is such a code:
<template>
<div class="chart"
v-bind:style="chartStyleObject">
</div>
</template>
<script>
export default{
data () {
return {
chartStyleObject: {
width: this.$store.state.chartStyleObject.width,
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
},
},
}
}
And such a repository:
const axios = require("axios");
export const state = () => ({
chartStyleObject: {
height: '247px',
width: '500px',
marginTop: '15px',
marginRight: '0px',
marginBottom: '0px',
marginLeft: '15px',
},
});
export const mutations = {
changeChartDraggableEventState (state, EventState) {
state.chartDraggableEventState = EventState;
},
changeChartHeight (state, height) {
state.chartStyleObject.height = height;
},
changeHeightWrapper (state, HeightWrapper) {
state.chartStyleObject.HeightWrapper = HeightWrapper;
},
changeWidthWrapper (state, WidthWrapper) {
state.chartStyleObject.WidthWrapper = WidthWrapper;
},
changeChartMarginLeft (state, MarginLeft) {
state.chartStyleObject.marginLeft = MarginLeft;
},
changeChartMarginTop (state, MarginTop) {
state.chartStyleObject.marginTop = MarginTop;
},
};
Problem:
If I change the state of the repository through mutations, then the properties of the repository change correctly.
But!
The data properties on which the same storage properties are tied for some reason does not change.
(Despite the fact that repository property was changed)
My question is:
Why does this happen - if dates property, as well as repositories property, in theory, should be reactive?
And which approach is the most correct in this case to solve this problem? (writing directly the storage properties in the code seems like a very cumbersome decision.)
When you assign the values in
chartStyleObject: {
width: this.$store.state.chartStyleObject.width, // here
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
},
you are assigning values to the width, height and so on. You assign to them the current values of the state variables.
If you want the properties of chartStyleObject to change whenever the store's state changes, either map the state directly in the template (or wheverever you use it) or create a computed:
export default {
computed: {
chartStyleObject() {
return {
width: this.$store.state.chartStyleObject.width,
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
};
},
},
}
I want to include a mixin within a nested element in TypeStyle.
The mixin is working great, on the main / root element, but not on a nested element.
export const fontSize = (value: number) => {
const valueStr = value + 'px';
return {
fontSize: valueStr
}
};
export const warning = style(
fontSize(15), {
$nest: {
'& span': ( fontSize(12), {
backgroundColor: 'yellow'
})
}
});
<div className={warning}>
This text is formatted correctly
<span>this text is not</span>
</div>
I'm not sure if it's even possible to pass mixins to a nested element. I can give the span element an extra class, but that would be more code.
If the element is nested, you obviously want to go for the nested selector >, the & selector could for instance be used for :hover:
// fontSize function given by author
const fontSize = (value: number) => {
const valueStr = value + 'px';
return {
fontSize: valueStr
}
};
// cleaner definition of fontSize function
const fontSizeFunc = (value: number) => ({ fontSize: `${value} px` });
// correct styling object using fontSize function
export const warning = {
...fontSize(15),
$nest: {
">": {
span: {
backgroundColor: "yellow",
...fontSize(12),
},
},
},
});
// correct styling object not using fontSize function
export const warning = {
fontSize: 15,
$nest: {
">": {
span: {
backgroundColor: "yellow",
fontSize: 12,
},
},
},
});
EDIT: Added usage of fontSize function which returns an object, thus requiring the spread operator to yield a correct JS object.
I am trying to run a few simple animations using react-native-animatable library. (But I believe the question should be generic to any react animations so adding other tags as well.)
The problem is, in the first time, the image animates just as expected. But when aimed to start second animation animation with the gesture, the image translation starts from its original coordinates.
A search yielt, in Android development (which is obviously not my case) there seems a method, setFillAfter which sets the coordinate after the animation.
My question is, how to set the location (left / top values for example) to the final translated point so that consecutive animation starts from the point the previous translation left.
The expo snack for below code block is here.
import * as React from 'react';
import { Image, StyleSheet, ImageBackground } from 'react-native';
import * as Animatable from 'react-native-animatable';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import testImg from './test.png';
import backImg from './back.png';
export default class App extends React.Component {
onTestMove(event) {
this.testAnimRef.transitionTo({
translateX: event.nativeEvent.translationX,
translateY: event.nativeEvent.translationY,
}, 0);
}
render() {
return (
<ImageBackground source={backImg} style={{ flex: 1 }} >
<PanGestureHandler
key={`test`}
onGestureEvent={(e) => { this.onTestMove(e) }}
onHandlerStateChange={e => { }}
>
<Animatable.View style={styles._animatable_view}
ref={((ref) => { this.testAnimRef = ref }).bind(this)}
useNativeDriver={true}
>
<Image source={testImg} style={styles._image} />
</Animatable.View>
</PanGestureHandler>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
_image: {
width: 50,
height: 25,
resizeMode: 'contain',
backgroundColor: 'black',
borderColor: 'gainsboro',
borderWidth: 2,
},
_animatable_view: {
position: "absolute",
top: 200,
left: 100,
},
});
I had the same problem trying to move around some cards in a view, and upon further dragging, they would reset to their origin.
My theory is/was that while the translated view would have its x / y coordinates translated, this would not apply to the parent of that view, and so the animated event passed from that component would initially have the original coordinates (nuke me if I'm wrong here)
So my solution was to keep an initial offset value in state, and maintain this every time the user releases the dragged motion
_onHandleGesture: any
constructor(props: OwnProps) {
super(props)
this.state = {
animationValue: new Animated.ValueXY({ x: 0, y: 0 }),
initialOffset: { x: 0, y: 0 },
}
this._onHandleGesture = (e: PanGestureHandlerGestureEvent) => {
this.state.animationValue.setValue({
x: e.nativeEvent.translationX + this.state.initialOffset.x, <- add initial offset to coordinates passed
y: e.nativeEvent.translationY + this.state.initialOffset.y,
})
}
}
_acceptCard = (cardValue: number) => {
const { targetLocation, onAccept } = this.props
const { x, y } = targetLocation
onAccept(cardValue)
Animated.spring(this.state.animationValue, {
// Some animation here
}).start(() => {
this.setState({ initialOffset: targetLocation }) // <- callback to set state value for next animation start
})
}
and the render method
<PanGestureHandler
onHandlerStateChange={this.onPanHandlerStateChange}
onGestureEvent={this._onHandleGesture}
failOffsetX={[-xThreshold, xThreshold]}
>
<Animated.View
style={{
position: "absolute",
left: 0,
top: 0,
transform: [{ translateX: this.state.animationValue.x }, { translateY: this.state.animationValue.y }],
}}
>
<CardTile size={size} content={content} layout={layout} backgroundImage={backgroundImage} shadow={shadow} />
</Animated.View>
</PanGestureHandler>
This example is based on the react-native-gesture-handler library, but the concept should apply to other solutions.
Dont know if this way is advisable, though it is functional.
Hope this helps!
I'm unable to animate the borderRadius property in a ReactNative Image, it seems to only re-render the image as the animation completes. It fades out on animation start, and fades back in on animation completion. This only happens on Android; on iOS the animation plays properly.
I am trying to animate a circle expanding into a square by animating the borderRadius:
constructor(props) {
super(props);
this.state = {
borderRadius: new Animated.Value(ALBUM_CIRCLE_DIAMETER /2)
};
}
_zoomIn = () => {
Animated.timing(
this.state.borderRadius,
{
toValue: 0,
duration: ZOOM_ANIMATION_DURATION_MS,
easing: Easing.linear
}
).start()
}
And the markup:
<Animated.Image
style={[
styles.albumArtCircle,
{ width: this.state.albumArtWidth },
{ height: this.state.albumArtHeight },
{ borderRadius: this.state.borderRadius },
]}
resizeMode='contain'
source={require('../images/sampleAlbum.jpg')}>
</Animated.Image>
Right! Remove resizeMode property. This will solve your problem
Removing resizeMode='contain' made this work.