I'm trying to animate fontWeight of an Animated.Text but can't get it to work.
1. Interpolating
const titleFontWeight = this.positionTitle1.x.interpolate({
inputRange: [-0.3 * SCREEN_WIDTH, 0],
outputRange: ['400', '600']
});
render() {
return (
<Animated.Text style={{ fontWeight: titleFontWeight }}>
Title
</Animated.Text>
);
}
With this solution the effect of the change won't happen until the whole animation (i.e. the animation of this.positionTitle1) is done and I get a
Warning: Failed prop type: Invalid prop 'fontWeight' of value '377.333' supplied to text [...].
2. Animated.timing
constructor() {
super();
this.fontWeight = new Animated.Value(400);
}
animateFontWeight() {
Animated.timing(this.fontWeight, {
toValue: 600,
duration: 500
}).start();
}
render() {
return (
<Animated.Text style={{ fontWeight: `${this.fontWeight._value}` }}>
Title
</Animated.Text>
);
}
For this solution the effect also doesn't show until the animation is done.
Is there any solution to this?
Try this
Setup Text
<Animated.Text
style={{fontWeight: this.fontWeightAnimation.interpolate({
inputRange: [300, 900],
outputRange: ['300', '900'],
easing: value => {
const thousandRounded = value * 1000;
if (thousandRounded < 300) {
return 0;
}
if (thousandRounded < 600) {
return 0.5;
}
return 1;
}
})}}> Sample Text </Animated.Text>
Init Animation : this.fontWeightAnimation = new Animated.Value(300);
Start Animation :
Animated.timing(this.fontWeightAnimation, {
toValue: 900,
duration: 3000
}).start();
As it has been mentioned above, fontWeight only accept fixed string value, ex.: '400', '800' or 'normal', 'bold'. To achieve your goal, you can simply using setState at the same time as your animation start.
startAnimation() {
Animated.parallel([
Animated.timing(this.state.translate, {
toValue: -27,
duration: 200,
}),
Animated.timing(this.state.color, {
toValue: 1,
duration: 300,
}),
]).start();
this.setState({
fontWeight: '800'
});};
stopAnimation() {
this.state.translate.setValue(0);
this.state.color.setValue(0);
this.setState({
fontWeight: '400'
});};
Related
Can any body help with How to create Tables in Phaser-3(Priority) / Canvas.
Table like this.
Without styling is also ok. Just I want to know how we can create table in Phaser-3(Priority) / Canvas.
You can try to Rex UI Plugin
Here you can find a DEMO
Other demos (scrolling, fix-width-sizer and so on..) available HERE.
HTML
<footer><div id=version></div></footer>
CSS
html, body {
height: 100%;
}
body {
margin: 0;
padding: 0;
background: #222;
color: #eee;
font: caption;
}
#version {
position: absolute;
left: 5px;
top: 605px;
}
JS
const Random = Phaser.Math.Between;
const COLOR_PRIMARY = 0x4e342e;
const COLOR_LIGHT = 0x7b5e57;
const COLOR_DARK = 0x260e04;
class Demo extends Phaser.Scene {
constructor() {
super({
key: 'examples'
})
}
preload() {
this.load.scenePlugin({
key: 'rexuiplugin',
url: 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/plugins/dist/rexuiplugin.min.js',
sceneKey: 'rexUI'
});
}
create() {
this.print = this.add.text(0, 0, '');
var db = createDataBase(400);
var tabs = this.rexUI.add.tabs({
x: 400,
y: 300,
panel: this.rexUI.add.gridTable({
background: this.rexUI.add.roundRectangle(0, 0, 20, 10, 10, COLOR_PRIMARY),
table: {
width: 250,
height: 400,
cellWidth: 120,
cellHeight: 60,
columns: 2,
mask: {
padding: 2,
},
},
slider: {
track: this.rexUI.add.roundRectangle(0, 0, 20, 10, 10, COLOR_DARK),
thumb: this.rexUI.add.roundRectangle(0, 0, 0, 0, 13, COLOR_LIGHT),
},
// scroller: true,
createCellContainerCallback: function (cell) {
var scene = cell.scene,
width = cell.width,
height = cell.height,
item = cell.item,
index = cell.index;
return scene.rexUI.add.label({
width: width,
height: height,
background: scene.rexUI.add.roundRectangle(0, 0, 20, 20, 0).setStrokeStyle(2, COLOR_DARK),
icon: scene.rexUI.add.roundRectangle(0, 0, 20, 20, 10, item.color),
text: scene.add.text(0, 0, item.id),
space: {
icon: 10,
left: 15
}
});
},
}),
leftButtons: [
createButton(this, 2, 'AA'),
createButton(this, 2, 'BB'),
createButton(this, 2, 'CC'),
createButton(this, 2, 'DD'),
],
rightButtons: [
createButton(this, 0, '+'),
createButton(this, 0, '-'),
],
space: {
leftButtonsOffset: 20,
rightButtonsOffset: 30,
leftButton: 1,
},
})
.layout()
//.drawBounds(this.add.graphics(), 0xff0000);
tabs
.on('button.click', function (button, groupName, index) {
switch (groupName) {
case 'left':
// Highlight button
if (this._prevTypeButton) {
this._prevTypeButton.getElement('background').setFillStyle(COLOR_DARK)
}
button.getElement('background').setFillStyle(COLOR_PRIMARY);
this._prevTypeButton = button;
if (this._prevSortButton === undefined) {
return;
}
break;
case 'right':
// Highlight button
if (this._prevSortButton) {
this._prevSortButton.getElement('background').setFillStyle(COLOR_DARK)
}
button.getElement('background').setFillStyle(COLOR_PRIMARY);
this._prevSortButton = button;
if (this._prevTypeButton === undefined) {
return;
}
break;
}
// Load items into grid table
var items = db
.chain()
.find({
type: this._prevTypeButton.text
})
.simplesort('id', {
desc: (this._prevSortButton.text === '-') // sort descending
})
.data();
this.getElement('panel').setItems(items).scrollToTop();
}, tabs);
// Grid table
tabs.getElement('panel')
.on('cell.click', function (cellContainer, cellIndex) {
this.print.text += cellIndex + ': ' + cellContainer.text + '\n';
}, this)
.on('cell.over', function (cellContainer, cellIndex) {
cellContainer.getElement('background')
.setStrokeStyle(2, COLOR_LIGHT)
.setDepth(1);
}, this)
.on('cell.out', function (cellContainer, cellIndex) {
cellContainer.getElement('background')
.setStrokeStyle(2, COLOR_DARK)
.setDepth(0);
}, this);
tabs.emitButtonClick('left', 0).emitButtonClick('right', 0);
}
update() {}
}
var createDataBase = function (count) {
var TYPE = ['AA', 'BB', 'CC', 'DD'];
// Create the database
var db = new loki();
// Create a collection
var items = db.addCollection('items');
// Insert documents
for (var i = 0; i < count; i++) {
items.insert({
type: TYPE[i % 4],
id: i,
color: Random(0, 0xffffff)
});
}
return items;
};
var createButton = function (scene, direction, text) {
var radius;
switch (direction) {
case 0: // Right
radius = {
tr: 20,
br: 20
}
break;
case 2: // Left
radius = {
tl: 20,
bl: 20
}
break;
}
return scene.rexUI.add.label({
width: 50,
height:40,
background: scene.rexUI.add.roundRectangle(0, 0, 50, 50, radius, COLOR_DARK),
text: scene.add.text(0, 0, text, {
fontSize: '18pt'
}),
space: {
left: 10
}
});
}
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Demo
};
var game = new Phaser.Game(config);
I am using react-navigation Transitioner to create a custom StackNavigator. When using useNativeDriver: true in my transition configuration, the animation for the transition only runs the first time. When set to false, it works as expected.
Note: Whilst setting it to false does fix my problem, I get choppy performance on Android without it, even in production mode.
Below snippet is my navigation view
render() {
return (
<Transitioner
configureTransition={this._configureTransition}
navigation={this.props.navigation}
render={this._render}
/>
);
}
_configureTransition = () => {
return { useNativeDriver: true };
}
_render = (transitionProps) => {
return transitionProps.scenes.map(scene => this._renderScene(transitionProps, scene));
}
_renderScene = (transitionProps, scene) => {
const { layout, position } = transitionProps;
const { index } = scene;
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [layout.initWidth, 0, 0],
});
const animationStyle = {
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: '#FFF',
transform: [{ translateX }],
};
const Scene = this.props.router.getComponentForRouteName(scene.route.routeName);
return (
<Animated.View key={scene.key} style={animationStyle}>
<Scene />
</Animated.View>
);
}
Below is a screen cap of the problem. Note how the first transition is animated, whilst future ones are not (the 'back' navigation should be animated too)
I have an array of texts that I want to flash on a blank screen, one after the other with animations. Something like:
state = {
meditations: ["Take a deep breath", "embrace this feeling", "breath
deeply", ...]
}
I want to show only one string at a time, and animate their opacity. So a string fades in and fades out, then the next string, and so on.
I am new to react native and quite confused about how to go about this. Please, how may I approach this, I have read the docs but still not clear how to.
Below is what I have tried, I modified this from the docs but it shows everything at once. I'm still trying to see how I can make them animate one after the other, showing only one at a time. Thanks for your help in advance.
import React from 'react';
import { Animated, Text, View } from 'react-native';
class FadeInView extends React.Component {
state = {
fadeAnim: new Animated.Value(0), // Initial value for opacity: 0
}
renderMeditations() {
let { fadeAnim } = this.state;
return this.props.meditations.map((meditation, index) => {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 2, // Animate to opacity: 1 (opaque)
duration: 10000, // Make it take a while
}
).start(() => {
this.setState({ fadeAnim: new Animated.Value(0) })
}); // Starts the animation
return (
<Animated.Text // Special animatable View
key={index}
style={{
...this.props.style,
opacity: fadeAnim, // Bind opacity to animated value
}}
>
{meditation}
</Animated.Text>
)
})
}
render() {
return (
<View style={{flex: 1}}>
{this.renderMeditations()}
</View>
);
}
}
export default class App extends React.Component {
state = {
meditations: ["Take a deep breath", "Calm down", "Relax", "Tell yourself all will be fine"]
}
render() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<FadeInView meditations={this.state.meditations} style={{fontSize: 28, textAlign: 'center', margin: 10}} />
</View>
)
}
}
After much toil with this, I was able to solve it with react-native-animatable like so:
import React from "react";
import {
View,
Text,
Animated
} from "react-native";
import * as Animatable from 'react-native-animatable';
class VideoScreen extends React.Component {
state = {
meditations: ["Take a deep breath", "embrace this feeling", "breath
deeply"],
index: 0
};
render() {
const { meditations, index } = this.state;
return (
<View style={{flex: 1}}>
<Animatable.Text
key={index}
animation={'fadeIn'}
iterationCount={2}
direction="alternate"
duration={2000}
onAnimationEnd={() => {
if (this.state.index < this.state.meditations.length - 1) {
this.setState({ index: this.state.index + 1});
}
}}
style={{
position: "absolute",
left: 0, right: 0,
bottom: 40
}}>
{meditations[index]}
</Animatable.Text>
</View>
);
}
}
export default VideoScreen;
The map function executes all at once so basically you are rendering/returning all 3 items at the same time. I understand that your issue is that the animation is working tho.
If what you want is to show one text, then the other and so on I suggest iterating the index of your text array instead of using the map function.
Something like:
Execute Animation
Increase Index
Index = 0 if you are at the end of the array.
In a loop. Check setInterval, it might help you.
For the function components:-
we can use the above-metioned solutions. I am writing a function hopefully it will help you display a looping text with the animation
We will use this package for the animation https://github.com/oblador/react-native-animatable.
import {StyleSheet} from 'react-native';
import React, {useState} from 'react';
import * as Animatable from 'react-native-animatable';
const UserMessage = () => {
const [index, setIndex] = useState(0);
const meditations = [
'Take a deep breath',
'embrace this feeling',
'breath deeply',
];
return (
<Animatable.Text
key={index}
animation={'fadeIn'}
iterationCount={2}
direction="alternate"
duration={2000}
onAnimationEnd={() => {
if (index < meditations.length - 1) {
setIndex(index + 1);
} else {
setIndex(0);
}
}}
style={styles.messageStyle}>
{meditations[index]}
</Animatable.Text>
);
};
export default UserMessage;
const styles = StyleSheet.create({
messageStyle: {
textAlign: 'center',
fontSize: 18,
fontWeight: '500',
width: '80%',
color: '#1C1C1C',
marginBottom: 20,
minHeight: 50,
alignSelf: 'center',
},
});
I'm new to react-native and need some help with Animate.
Goal: to animate Image, so that it looks like its slowly breathing.(getting a little larger then smaller, then back again, constantly, like someone breathing in and out)
My images are stored in an array, inside newOrder() method:
newOrder(timeAsProp) {
const hour = timeAsProp.slice(0, 2);
let returnValue = [];
const yud = <Image key="yud" source={require('./img/yud.png')} style={Style.image} />;
const hey1 = <Image key="hey1" source={require('./img/hey1.png')} style={Style.image} />;
const vav = <Image key="vav" source={require('./img/vav.png')} style={Style.image} />;
const hey2 = <Image key="hey2" source={require('./img/hey2.png')} style={Style.image} />;
return (
<View style={Style.displayContainer}>{returnValue}</View>
);
called in the render method, like this:
{this.newOrder(parsedTime)}
its four seperate images, which are rendered and displayed together on one line.
it looks like this:
letters being rendered to one word:
its important that the Image as a whole, should be breathing together in unison, and not each image on its own.
heres a screen pic so you see what the image looks like, if that will help you understand the best method to make it look alive:
edit:
something that would add to the animation i think, would be two things:
1)size getting larger and smaller
2)actual color patch on the letters slightly moving, maybe closer and further, like zooming in and out or something like that.
i think those two together would make the breathing 3d.
so im interested in hearing peoples opinions how to do this...
thnks!
Use a sequence of animations in a loop.
In this example I am breathing a text.
First change the opacity from 1 to 0, then, change the opacity back to 1.
You can use this principle to change other properties, like width and height.
import React, {Component} from 'react'
import {
Animated,
Easing
} from 'react-native'
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
opacity: new Animated.Value(1)
}
}
componentDidMount() {
Animated.loop(
Animated.sequence([
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 1000,
ease: Easing.linear,
useNativeDriver: true
}),
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 1000,
ease: Easing.linear,
useNativeDriver: true
})
])
).start();
}
render() {
return(
<Animated.View style={{opacity: this.state.opacity}}>
<Text>I'm breathing</Text>
</Animated.View>
);
}
}
So for an infinite animation (that you can stop on your own), you can set the width and height of all of the images to the same interpolated Animated value. To generate a breathing effect, one possible way to do this is to tie two animation functions together with one increasing and the other decreasing. For example:
import React, { Component } from 'react';
import { View, StyleSheet, Animated, Image, Easing } from 'react-native';
import { Constants } from 'expo';
const AnimatedImage = Animated.createAnimatedComponent(Image);
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
size: new Animated.Value(1)
}
}
componentDidMount () {
this._loopAnimationUp();
}
// The animation functions. Initial and end values can be anything (not just 1, 10, but remember to use the same value and flip them:
_loopAnimationUp() {
this.state.size.setValue(1);
Animated.timing(this.state.size, {
toValue: 10,
duration: 5000,
easing: Easing.linear
}).start((o) => {
if (o.finished) {
this._loopAnimationDown();
}
});
}
_loopAnimationDown() {
this.state.size.setValue(10);
Animated.timing(this.state.size, {
toValue: 1,
duration: 5000,
easing: Easing.linear
}).start((o) => {
if (o.finished) {
this._loopAnimationUp();
}
});
}
render() {
const size = this.state.size.interpolate({
inputRange: [1, 10],
outputRange: [10, 50],
extrapolate: 'clamp',
});
return (
<View style={styles.container}>
<AnimatedImage
style={[styles.image, {
width: size,
height: size,
}]}
source={{uri: 'http://placekitten.com/g/200/200'}}
/>
<AnimatedImage
style={[styles.image, {
width: size,
height: size,
}]}
source={{uri: 'http://placekitten.com/g/200/200'}}
/>
<AnimatedImage
style={[styles.image, {
width: size,
height: size,
}]}
source={{uri: 'http://placekitten.com/g/200/200'}}
/>
<AnimatedImage
style={[styles.image, {
width: size,
height: size,
}]}
source={{uri: 'http://placekitten.com/g/200/200'}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
flexDirection: 'row',
},
image: {
justifyContent:'center',
backgroundColor:'transparent'
},
});
If you need to later stop the animation, you can use:
this.state.size.stopAnimation();
You can see a working implementation of it here using placeholder images.
For the more math inclined, there is probably a way to accomplish this with a single looping animation and using interpolation in a more complex manner.
React-native introduce new Animated API, I want to make a loop animation such as a bubble scale up then scale down and repeat that progress.
However I can not figure it out. I've tried write some code like below
class TestProject extends React.Component {
constructor(): void {
super();
this.state = {
bounceValue: new Animated.Value(0),
v: 1,
};
}
componentDidMount() {
this.state.bounceValue.setValue(1.5);
let animation = Animated.timing(this.state.bounceValue, {
toValue: this.state.v,
});
setInterval(() => {
animation.stop();
if (this.state.flag) {
this.state.v = 0.5;
this.state.bounceValue.setValue(0.5);
}
else {
this.state.v = 1.5;
this.state.bounceValue.setValue(1.5);
}
animation.start();
}, 5000);
}
render(): ReactElement {
return (
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={{uri: 'http://image142-c.poco.cn/best_pocoers/20130517/91062013051716553599334223.jpg'}}
/>
<Animated.Text
style={[
styles.test,
{transform: [
{scale: this.state.bounceValue},
],}
]
}>
haha
</Animated.Text>
</View>
);
}
}
but not works very well.
Any suggestion will be appreciate.
There's now loop animation available:
Animated.loop(
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]),
{
iterations: 4
}
).start()
I use the sequence method to pass an array of animations to cycle and then repeat the function.
//this.state.animatedStartValue = 0;
function cycleAnimation() {
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]).start(() => {
cycleAnimation();
});
}
If I'm toggling that animation on it's own it will fade in/out, however I layer it on top of a base to mimic an active state or hotspot-style button
<TouchableOpacity>
<Animated.Image
source={activeImageSource}
style={this.state.animatedStartValue}}
/>
<Image source={nonActiveImageSource}
/>
</TouchableOpacity>
React Native Sequence Documentation
improved version of #bcomerford answer
//this.state.animatedStartValue = 0;
function cycleAnimation() {
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]).start(event => {
if (event.finished) {
cycleAnimation();
}
});
}
Try something like this:
componentDidMount() {
this.bootAnimation();
}
bootAnimation() {
this.animation = Animated.loop(
Animated.timing(this.state.progress, {
toValue: 1,
duration: 5000
})
).start();
}
It seems that 'looping' is not supported by the Animated api for now.
I managed to do that by start the animation again when it finished.
startAnimation() {
Animated.timing(this._animatedValue, {
toValue: 100,
duration: 1000,
}).start(() => {
this.startAnimation();
});
}
Looking forward to a better solution...
You can set another animation then call the animation again:
An example I did to fade text in and out:
textAnimate: function() {
Animated.timing(
this.state.textOpacity,
{
toValue: 0.3,
duration: 500,
}
).start(() => {
Animated.timing(
this.state.textOpacity,
{
toValue: 1,
duration: 500,
}
).start(() => {
this.textAnimate();
});
});
},
componentDidMount: function() {
this.state.textOpacity.setValue(1)
this.textAnimate();
},
Not sure if it's hacky, but I use this:
Animated.spring(this.state.rotation, {
toValue: 5,
stiffness: 220, // the higher value, the faster the animation
damping: 0.000001, // never stop wiggle wiggle wiggle
}).start();
It's creating spring animation that will never (technically, for a very very very long time) stop waving.
For most of my cases it was enough. Also it has great performance as it does not require any JS tread action ever during animation.
If eventually you'd like to stop it gracefully:
Animated.spring(this.state.rotation, {
toValue: 0,
stiffness: 220, // the higher value, the faster the animation
damping: 10, // never stop wiggle wiggle wiggle
}).start();
And it'll nicely 'slow down' until it stops.
Here's another example for an infinite animation using hooks and iterations set to "infinity". Avoids the use of the recursion in previous answers which sometimes led to funky behaviour during e2e testing for us.
const rotation = React.useRef(new Animated.Value(0)).current;
function runAnimation() {
return Animated.loop(
Animated.timing(rotation, {
toValue: 1,
duration: 1200,
easing: Easing.linear,
useNativeDriver: true,
}),
{resetBeforeIteration: true, iterations: Number.MAX_SAFE_INTEGER},
);
}
React.useEffect(() => {
const animation = runAnimation();
return () => animation.stop();
}, []);