I want to move images inside the view but the images should not go beyond the boundaries of the view(screen)
like that:
https://snack.expo.dev/#aisylu24/draggable-image-within-parent-boundaries-
click to see screenshot - i want to move only inside gray view
but I need to use Animated or Reanimated with gesture-handler and Functional component
Maybe I need to use layout for view but I don't know how to do it?
this is my snack where I need to do like that:
https://snack.expo.dev/#aisylu24/lookbook
Click on one of the pictures to see it
You can use a React-native gesture handler for capturing events.
https://docs.swmansion.com/react-native-gesture-handler/docs/gesture-handlers/api/pan-gh/
For animated value you can use default Animated from react-native
and for boundary fixing, you need to learn the concept of interpolation,
translateX.interpolate({
inputRange: [0, 100],
outputRange: [0, 100],
}),
translateY.interpolate({
inputRange: [0, 100],
outputRange: [0, 100],
}),
instead of [0,100] you need to add a range based on the area you want.
Related
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;
When using react-native animated flatlist to create a carousel, all works fine with the interpolate as follows:
const translateY = this.state.scrollX.interpolate({ inputRange, outputRange: [0, -60, 0] });
But, when we call out to a separate intent for permissions or going off to a settings page, the X position of my animated flatlist appears to reset to 0 and the object I'm animating (in a carousel) drops to the bottom of the view.
Has anyone got any idea on how to handle that? I don't know if it's because the scrollX state setting is lost or what...
Thanks
Simon
Just in case anyone else is using the Animated.FlatList in a similar way to us, the issue related to the useNativeDriver setting. When set to true and the app was put into the background with an React Native Intent, the FlatList flatlined and lost it's interpolated Y coordinate. When setting to false, things worked as expected.
Thanks
Simon
I am trying to create custom animation. I have hearth image which goes from bottom left corner to top right one. I will be animating top and bottom values of image to get it across the screen. The only catch is that I want it to rotate a little bit in the middle of a road, and then rotate back to first state. Is such animation doable? If so, could you give me advise how can i code it?
Cheers!
You can rotate the image with the rotate property of transform and use your animated value there. Example:
var interpolatedRotateAnimation = this._animatedValue.interpolate({
inputRange: [0, 100],
outputRange: ['0deg', '360deg']
});
You can find an example here
I have added a TimeLineMax to a scene that I am working on. The functionality is working great but I am having trouble with a few details.
I would like my scene to pin like this site http://www.google.com/inbox/#bundles . By this I want multiple pins within one scene so that a user can't scroll through my animations without viewing them.
Here is a demo site of my work so far : https://so-staging.herokuapp.com/users/sign_in#publisher-demo-container
You can see my progress if you scroll down. Three steps will pop up and then animate away. I also have adjusted the background position of #publisher-demo-steps based on scroll.
However this isn't the desired goal. I would like this:
1. Pin #publisher-demo
2. Fire step 1 animated background-position on scroll.
3. Fire step 2
4. Fire step 3
I would like each step to be pinned so that a user can't go to the next step until the animation is complete.
I know this is confusing and I have been staring at it way too long. Thanks for the help. Here is my scrollmagic and GSAP code.
var controller = new ScrollMagic();
var tween = new TimelineMax()
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "50% 23%"}))
.add(TweenMax.to(".blue-circle", 1, {display: "block"}))
.add(TweenMax.to(".blue-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "22% 52%"}))
.add(TweenMax.to(".red-circle", 1, {display: "block"}))
.add(TweenMax.to(".red-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.add(TweenMax.to("#publisher-demo-steps", 0.5, {backgroundPosition : "76% 50%"}))
.add(TweenMax.to(".green-circle", 1, {display: "block"}))
.add(TweenMax.to(".green-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}));
var scene = new ScrollScene({triggerElement: "#publisher-demo", duration: 4000, triggerHook: -100})
.setPin("#publisher-demo")
.setTween(tween)
.addTo(controller);
If I understand you correctly you would like to trigger the animations to play unbound from scroll progress.
The way you do this is by not linking the scene that does the pin.
As soon as a scene has a duration it will link animation progress to scroll progress.
Then you just add a scene for each animation trigger point.
i.e. like this:
new ScrollScene({triggerElement: "#trigger-element", duration: 4000, triggerHook: 0})
.setPin("#publisher-demo")
.addTo(controller);
new ScrollScene({triggerElement: "#trigger-element", triggerHook: 0})
.setTween(new TimelineMax()
.to("#publisher-demo-steps", 0.5, {backgroundPosition : "50% 23%"})
.to(".blue-circle", 1, {display: "block"})
)
.addTo(controller);
new ScrollScene({triggerElement: "#trigger-element", triggerHook: 0, offset: 300)
.setTween(TweenMax.to(".blue-circle", 1, {className: "+=animated zoomOut", display: "none", delay:3}))
.addTo(controller);
General notes:
As you see I used a trigger element that is different from the pinned element. It should be positioned absolute and located at the same position as the pinned element. the reason I do this is, because the pinned element moves and would supply a wrong start position for the other scenes.
A triggerHook of -100 doesn't make any sense. The value can by definition only be between 0 and 1.
instead of TimelineMax().add(TweenMax.to()) you can use the shorthand TimelineMax().to() (see http://greensock.com/docs/#/HTML5/GSAP/TimelineMax/to/)
Note, that ScrollMagic 2 has been released for a while now. The syntax is very similar so you should consider upgrading.
I'm using Flexslider for a project of gallery and I want to modify the navigation system.
On keypress/swipe/click on arrows, four images displayed disappear and are replaced by four new.
Is it possible to modify the behavior of the navigation to move images one by one ?
Thank you very much for your help !
Z.
You may want to use property move, which is defined as
//{NEW} Integer: Number of carousel items that should move on
animation. If 0, slider will move all visible items.
So, your code will look like this
$(window).load(function() {
$('.slidewidget1').flexslider({
animation: "slide",
animationLoop: true,
itemWidth: 210,
controlNav: false,
itemMargin: 0,
slideshow: false,
move: 1,
minItems = 4,
maxItems = 4
});
});
plus, of course, your customization of width, etc.
Documentation