How to create a simple animation effect - react-native

Is there a code sample available that illustrates how to use a 2D transform (such as rotate and scale) with a JPG in a react-native application, perhaps with the code in the tutorial as a starting point?
If possible, it would be helpful to see code for two scenarios:
1) automatically apply a transform when the app is launched
2) apply a transform after different types of user gestures
At some point in the future it would be interesting to see how to create 3D transforms and animation effects.

Update: You can see the entire example in my sample app here: https://github.com/grgur/react-native-memory-game
Animation is now AnimationExperimental so we'll need to modify zvona's solution.
First, make sure RCTAnimationExperimental is a linked library
If not, then follow these steps:
Navigate to node_modules/react-native/Libraries/Animation/
Drag and drop RCTAnimationExperimental.xcodeproj to Libraries (should look like the image above)
Click on your project name (in the example above, my project name is Memory)
Switch to the Build Phases tab
Expand Libraries/RCTAnimationExperimental.xcodeproj/Products
Drag libRctAnimationExperimental.a to Link Binary With Libraries
Ok, the hardest part is now over. Head over to your JavaScript file. Animation is no longer part of the react-native package so we have to include it explicitly.
var React = require('react-native');
var AnimationExperimental = require('AnimationExperimental');
Alright, champ, you're ready to animate. Make sure you know what you're animating. The view you will be animating is referred to as node.
AnimationExperimental.startAnimation({
node: this.refs.image,
duration: 400,
easing: 'easeInQuad',
property: 'opacity',
toValue: 0.1,
});
And that's it!
At the moment of writing, available properties are: opacity, position, positionX, positionY, rotation, scaleXY

Currently, this is a bit more complex process and I'm planning to write a blog post about that. However, as a brief starter, I write something here.
First problem is that RCTAnimation / RCTAnimationManager is not present at all, if you've created your project with react-native init [ProjectName] (https://github.com/facebook/react-native/issues/226).
You need to add it in XCode from a plus sign in top left corner: "Add Files to [ProjectName]". Then you navigate to node_modules > Libraries > Animation > RCTAnimation.xcodeproj. After it's imported, you need to drag it under Libraries in your project.
Then you need to open tab Build Phases. There you have menu Link Binary With Libraries (x items). Drag from Products under RCTAnimation.xcodeproj file named libRCTAnimation.a to the menu.
Now, you can build your project to support animations. I'm not that familiar with XCode, so there could be a even more simple way of achieving this, but I got it sorted like this.
Second Problem is that not all the available (or planned) functionality is there. At least I ran through the jungle of trials and errors before I got anything on the screen.
Try e.g. this code at first to get fully proofed that animations are working:
var {
Animation,
AppRegistry,
StyleSheet,
Text,
View
} = React;
var styles = StyleSheet.create({
test: {
width: 400,
height: 400,
backgroundColor: 'blue',
opacity: 0
}
});
var AnimationTest = React.createClass({
componentDidMount () {
Animation.startAnimation(this.refs['this'], 400, 0, 'linear', {opacity: 1});
},
render () {
return (
<View ref='this' style={styles.test}>
<Text>Just an animation test</Text>
</View>
)
}
});
AppRegistry.registerComponent('AnimationTest', () => AnimationTest);
This should get you going. If you need any further assistance, please notify me.
If I ever succeed in writing a more complete instructions in a form of a blog article, I'll update it to this answer.

Check out the 2048 demo application for example usage of the RCTAnimation library:
https://github.com/facebook/react-native/tree/master/Examples/2048
It doesn't use any especially complex transforms, but does animate position, opacity, and scaleXY of various elements with code that looks like this:
Animation.startAnimation(this.refs['this'], 300, 0, 'easeInOutQuad', {scaleXY: [1, 1]});

Related

How can I use react-native-gesture-handler to handle react-native-skia touches inside a ScrollView?

I have a ScrollView containing several graphs made with react-native-skia. The graphs are interactable, i.e. I can touch them and move an indicator on the graph along the x-axis of the graph.
My issue is that the whenever the ScrollView events fire (i.e. we scroll up/down), then the graph touch events are ignored which makes for bad UX.
Demo:
Here's a Snack with a reproducible demo: https://snack.expo.dev/#jorundur/supportive-raisins
FYI: For some reason for me the Canvas disappears after 1 second in the Snack, but if you make any change in the file and save (such add a newline somewhere), then it appears. It's fine if you run this locally. But that's some other problem we can ignore for the purpose of this discussion.
Description:
The demo is a react-native ScrollView large enough to make sure we have to scroll, the top component is a graph using react-native-skia. If we drag the cursor in the graph around, then the UX gets bad pretty quickly as the graph touch events seem to be ignored as soon as any vertical scrolling happens. I've tried playing around with ScrollView from react-native-gesture-handler but without luck.
To me, the expected behaviour would be for the graph to be interactable even while scrolling. I.e. if I'm pressing the graph and move my finger diagonally up/down I would expect the ScrollView to scroll and the graph cursor also to change its position accordingly. (I say diagonally since a straight vertical movement wouldn't change the cursor position in this graph.)
Much appreciated if anyone has any ideas on how to solve this! I couldn't work out how to do it via GestureDetector from react-native-gesture-handler like I've heard suggested.
Possible solution (?):
What I think I need to do is remove the onTouch={touchHandler} which I'm using currently in the react-native-skia Canvas component and instead get those touches via gesture detection from react-native-gesture-handler. I then need to make those gestures work simultaneously with the parent ScrollViews scroll event gestures. I've not had any luck implementing that unfortunately.
The solution was to do the following:
Don't use onTouch on Canvas, instead detect gestures via react-native-gesture-handler
Create a gesture and add a ref to it
Add the simultaneousHandlers prop to the ScrollView and use the ref there
This tells the ScrollView that its events should not be blocked by the touch events from the ref
To reiterate, what I wanted to do was to have the touch events of a ScrollView work simultaneously with touch events from a react-native-skia Canvas child component.
Code (relevant bits):
import * as React from 'react';
import {
GestureHandlerRootView,
ScrollView // Note that this is not imported from react-native
} from 'react-native-gesture-handler';
const App = () => {
// Create ref for the ScrollView to know what other gestures it should work simultaneously with.
// My use case required pan but this can be swapped for other gestures.
const panGestureRef = React.useRef<GestureType>(Gesture.Pan());
// The logic that used to be in `onTouch` on the Canvas is now here
const panGesture = Gesture.Pan()
.onChange((e) => {
// Do stuff, also use the other callbacks available as needed
})
.withRef(panGestureRef);
return (
<GestureHandlerRootView style={{ flex: 1 }}>{/* Don't forget this! It should be at the root of your project. */}
<ScrollView simultaneousHandlers={[panGestureRef]}>
<GestureDetector gesture={panGesture}>
<Canvas style={{ width: 200, height: 200 }}>
{/* Your interactive react-native-skia magic */}
</Canvas>
</GestureDetector>
</ScrollView>
</GestureHandlerRootView>
);
};
export default App;

How to stay in position when new messages are loaded in a ScrollView in React-Native?

I have a ScrollView containing messages (most recent messages are further) in a chat application.
I limit the number of pre-loaded messages, and I dynamically load a new batch when the Scroll View is scrolled to the top. So when new messages are loaded, the current scrollPos is at 0.
The problem is that when the new messages arrive, the scrollPos stays at 0, so the user is teleported to the oldest newly loaded message.
I have tried to deal with it by manually scrolling back down to the position using the size of the content change, but this is not satisfying as the user sees a back and forth scrolling.
Can someone think of a way to do this so that the user does not see any change when the new messages appear an can simply gradually scroll up to see them.
I found a way to do it.
The idea comes from the Invertible Scroll View component: https://github.com/expo/react-native-invertible-scroll-view
I didn't use the component but implemented the idea directly on the Scroll View to have minimal changes in my code.
To explain, we translate vertically the Scroll View using the style of the Scroll View and transform: [{ scaleY: -1 }]. We do the same for the children. Then, we revert the order of the messages.
In that setup, the scrollPos() measures from the visual bottom. To trigger the loading of the new messagges, now I use
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
The trick is that now, when the new messages appear on top, you have nothing to do as the distance from the user's point of view to the bottom does not change.
You can use the onContentSizeChange prop to scroll to the bottom anytime it detects a change in content size.
The scrollToEnd function may differ depending on RN version.
<ScrollView
...
onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
Ref: https://reactnative.dev/docs/scrollview#scrolltoend

Easiest way to trace a shape with touch in react native?

I am trying to do a confirmation screen on my react native app and I need the user to trace an ellipse in order to confirm their action - kinda like what hotel tonight does with their logo. Is there a library I can use to have the user trace over an svg?
Here is an example of what the user would be doing:
I found someone else trying to do this, I don't think that is the most creative approach, there was a way to do this in flash many years ago.
I know that SVG is being used for line art animation there are many tutorials out there:
https://medium.com/#sterling.meghan/svg-line-animation-for-beginners-51857c88357f
Also, there is a library for SVG called react-native-svg, the thing is SVG objects can be dragged in javascript
http://www.petercollingridge.co.uk/tutorials/svg/interactive/dragging/
So my idea to solve this would be this:
You have two layers one on top of each other.
The top one fills the entire screen and has a cut, that is the shape to be traced (the line art)
To get to the SVG object that is behind you can only do it through this cut. You can show a small circle on the starting point that is part of a big SVG colored shape that is under the cut, this shape is the second layer.
The user would start tracing but what he really is doing is dragging that SVG big object from one point to the next, he needs to follow the path like tracing because only if he does this he can drag the object through the hole. (He can only reach the object in the second layer through the hole)
The SVG object being drag has a different color from the top layer so when the user drags it gives the appearance of the path filling up.
I hope this helps you or at least gives you some ideas. Also, you could animate another SVG when the user completes the trace, with CSS line art animation. I would probably try this when I have the time.
I came across a similar situation in which I ended up using react-native-sketch-canvas
I made the user draw on the canvas & compared the output path with a predefined path. It was not a perfect solution but was good enough for my requirements.
For recognition you can use rn-gesture-recognizer built off of the rn-draw package :
https://www.npmjs.com/package/rn-gesture-recognizer
(https://www.npmjs.com/package/rn-draw)
And then you can for example create your perfect css shape over your svg :
https://codedaily.io/tutorials/22/The-Shapes-of-React-Native
Also, you can do other things like that :
https://codedaily.io/tutorials/55/Create-a-Draggable-Opacity-Changing-Circle-with-Reanimated-in-React-Native
Generally when we talk about working on SVG's the first library that comes to my mind is the D3 Js , in d3 you can follow the path of any shape in the svg and we can create interpolation , One such example is stated below , See through if this can help you in any ways.
<!DOCTYPE HTML>
<html lang="en">
<head>
</head>
<body>
<div id="loader_container"></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
function loader(config) {
return function() {
var radius = Math.min(config.width, config.height) / 2;
var tau = 2 * Math.PI;
var arc = d3.svg.arc()
.innerRadius(radius*0.5)
.outerRadius(radius*0.9)
.startAngle(0);
var svg = d3.select(config.container).append("svg")
.attr("id", config.id)
.attr("width", config.width)
.attr("height", config.height)
.append("g")
.attr("transform", "translate(" + config.width / 2 + "," + config.height / 2 + ")")
var background = svg.append("path")
.datum({endAngle: 0.33*tau})
.style("fill", "#4D4D4D")
.attr("d", arc)
.call(spin, 1500)
function spin(selection, duration) {
selection.transition()
.ease("linear")
.duration(duration)
.attrTween("transform", function() {
return d3.interpolateString("rotate(0)", "rotate(360)");
});
setTimeout(function() { spin(selection, duration); }, duration);
}
function transitionFunction(path) {
path.transition()
.duration(7500)
.attrTween("stroke-dasharray", tweenDash)
.each("end", function() { d3.select(this).call(transition); });
}
};
}
var myLoader = loader({width: 960, height: 500, container: "#loader_container", id: "loader"});
myLoader();
</script>
</body>
</html>
Source :
http://bl.ocks.org/MattWoelk/6132258
You can tweak the interpolation with any types , String , date anything. For Interpolation the below link can help
https://bl.ocks.org/mbostock/3173784
http://jsfiddle.net/SHF2M/
https://codepen.io/frcodecamp/pen/wxXypx
Build the outer svg shape as two ellipses connected by line on either sides , then we can use the ellipse path to interpolate using rotate positions , The rotate position should depend on the progress in confirmation screen.

Adding image as a label on edge in cytoscape.js

Created a graph using cytoscape.js. Need to add image as a label on edge.
After examination of
CanvasRenderer.drawElements in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-redraw.js#L406-L412
CanvasRenderer.drawEdgeText in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-label-text.js#L6-L31
CanvasRenderer.drawEdge in https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/src/extensions/renderer.canvas.drawing-edges.js
it seems that image label on edge is not supported right now.
One candidate where this feature might be added seems to be the CanvasRenderer.drawEdgeText function. The implementation might examine the text contained in the edge's content and if it looks like reference to an image (e.g. url) then draw it as image...
https://github.com/cytoscape/cytoscape.js/blob/v2.3.8/README.md
Contributing to Cytoscape.js
Cytoscape.js is an open source project, and anyone interested is encouraged to contribute to Cytoscape.js. We gladly accept pull requests. If you are interested in regular contributions to Cytoscape.js, then we can arrange granting you permission to the repository by contacting us.
If your pull request is a bugfix, please make changes to the master branch. Otherwise, please make changes to the next version's branch (i.e. unstable).
I know this is a late answer. but this will help somebody who looks for an answer as like me.
We can use icon fonts or fontawesome for this.
set the edges data as
edges = {
data:
id: "3f5cb5c4-43aa-4f4d-b816-fb4f279585c7"
label: "1 A \uf023 \uf022" //this is the fontawesome unicode chars for lock and notes icons
source: "1"
sourceName: "shipping"
target: "4"
targetName: "twilio.com"
value: 2
}
next in your cytoscape style, mention the font as fontawesome
{
selector: '.autorotate',
style: {
'edge-text-rotation': 'autorotate',
'font-size': '8px',
// 'color': '#000000',
'color': '#333333',
'font-family': 'FontAwesome, helvetica neue Cantarell',
'text-margin-x':'5px',
'text-margin-y':'5px',
// 'source-text-margin-x':'5px',
// 'source-text-margin-y':'5px'
}
}
Now your cytoscape graph will show edges with images as like this

Acitvity Indicator doesnt show up in ios 5 but it is visible in ios 4

I am using Titanium studio for development, acitvity indicator doesnt show up in ios 5 but it is visible in ios 4...please help
Code:-
var activityIndicator = Ti.UI.createActivityIndicator
({
style:Ti.UI.iPhone.ActivityIndicatorStyle.BIG,
top:45,
left:128,
font:{ fontSize:14, fontFamily:'Helvetica Neue', fontWeight:'bold'},
message:'loading..'
});
window.add(activityIndicator);
First a link to the docs. Now some explanation: once you add an activity indicator to a window or view, you also have to show it like this:
activityIndicator.show();
Then when youre done with it you can hide it like this:
activityIndicator.hide();
Also note that the BIG style is white and cant be seen on a white background.
As an addendum, this is bad javascript practice :
var activityIndicator = Ti.UI.createActivityIndicator
({ <----------- Never do this
.....
});
var activityIndicator = Ti.UI.createActivityIndicator({ <-- Thats better
.....
});
This may cause the interpreter to put a semi-colon after the first line, causing problems, and it just looks awful (this is not Obj-C, this is javascript). Refer to this talk by Kevin Whinnery on "Best Practices for Javascript."