Comments (13)
So I'm slowly getting somewhere:
https://gyazo.com/97ef4f578b95a7c1242e4a3710a4e6da
The above result is with the following (typescript) code, most of it copy+pasted from the "draggable" and "scaleAndRotate" examples:
import { Animated, StyleSheet, View } from 'react-native';
import {
PanGestureHandler,
PinchGestureHandler,
RotationGestureHandler,
ScrollView,
State,
} from 'react-native-gesture-handler';
const USE_NATIVE_DRIVER = false; // https://github.com/kmagiera/react-native-gesture-handler/issues/71
export class Sticker extends React.Component {
onPanGestureEvent: (...args: any[]) => void;
lastOffset: { x: number; y: number };
translateY: Animated.Value;
translateX: Animated.Value;
onTiltGestureEvent: (...args: any[]) => void;
lastTilt: number;
tiltStr: Animated.AnimatedInterpolation;
tilt: Animated.Value;
onRotateGestureEvent: (...args: any[]) => void;
lastRotate: number;
rotateStr: Animated.AnimatedInterpolation;
rotate: Animated.Value;
onPinchGestureEvent: (...args: any[]) => void;
lastScale: number;
scale: Animated.AnimatedMultiplication;
pinchScale: Animated.Value;
baseScale: Animated.Value;
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 }
);
/* Pan */
this.translateX = new Animated.Value(0);
this.translateY = new Animated.Value(0);
this.lastOffset = { x: 0, y: 0 };
this.onPanGestureEvent = Animated.event(
[
{
nativeEvent: {
translationX: this.translateX,
translationY: this.translateY,
},
},
],
{ 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);
}
};
onPanStateChange = event => {
if (event.nativeEvent.oldState === State.ACTIVE) {
this.lastOffset.x += event.nativeEvent.translationX;
this.lastOffset.y += event.nativeEvent.translationY;
this.translateX.setOffset(this.lastOffset.x);
this.translateX.setValue(0);
this.translateY.setOffset(this.lastOffset.y);
this.translateY.setValue(0);
}
};
render() {
const translateX = this.translateX;
const translateY = this.translateY;
const panStyle = {
transform: [{ translateX }, { translateY }],
};
return (
<PanGestureHandler
{...this.props}
onGestureEvent={this.onPanGestureEvent}
onHandlerStateChange={this.onPanStateChange}
id="dragbox"
>
<RotationGestureHandler
id="image_rotation"
simultaneousHandlers="image_pinch"
onGestureEvent={this.onRotateGestureEvent}
onHandlerStateChange={this.onRotateHandlerStateChange}
>
<PinchGestureHandler
id="image_pinch"
simultaneousHandlers="image_rotation"
onGestureEvent={this.onPinchGestureEvent}
onHandlerStateChange={this.onPinchHandlerStateChange}
>
<Animated.View
style={[panStyle, styles.container]}
collapsable={false}
>
<Animated.Image
style={[
styles.pinchableImage,
{
transform: [
{ perspective: 200 },
{ scale: this.scale },
{ rotate: this.rotateStr },
{ rotateX: this.tiltStr },
// { translateX: this.translateX },
// { translateY: this.translateY },
],
},
]}
source={{
uri:
'https://i.pinimg.com/736x/82/cf/b2/82cfb200c95adef00650e6450ef42925--pet-logo-cat-silhouette.jpg',
}}
/>
</Animated.View>
</PinchGestureHandler>
</RotationGestureHandler>
</PanGestureHandler>
);
}
}
export default Sticker;
const styles = StyleSheet.create({
container: {
// ...StyleSheet.absoluteFillObject,
// backgroundColor: 'black',
position: 'absolute',
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
},
pinchableImage: {
width: 250,
height: 250,
},
});
The Animated.View around the image seemed redundant, though, so I tried removing it and moving the translation transform to the image itself. It's functional, but I get these weird drawing errors on pan gestures:
https://gyazo.com/c4c66bd6bcd8f034b181ff68ac895fcf
The changed code:
{/* <Animated.View
style={[panStyle, styles.container]}
collapsable={false}
> */}
<Animated.Image
style={[
styles.pinchableImage,
{
transform: [
{ perspective: 200 },
{ scale: this.scale },
{ rotate: this.rotateStr },
{ rotateX: this.tiltStr },
{ translateX: this.translateX },
{ translateY: this.translateY },
],
},
]}
source={{
uri:
'https://i.pinimg.com/736x/82/cf/b2/82cfb200c95adef00650e6450ef42925--pet-logo-cat-silhouette.jpg',
}}
/>
{/* </Animated.View> */}
Any idea as to why?
from react-native-gesture-handler.
Hey @jhalborg! Glad to see how far have you managed to get with your demo app. Nice progress!
I'm just trying to understand what this issue is about and my understanding is that you managed to get around most of the gesture handler related issues. So my understanding is that you wanted to know why are you getting these visual artifacts while panning when you use Animated.Image as direct child instead of wrapping it in an Animated.View? If so then to be honest I don't know why this could be happening and would like to know if this is somehow related to gesture handler library. Would you be able to try to start an animation for translateX/translateY value instead of panning to see if this could be caused by gesture handler or maybe just related to animating transform property?
from react-native-gesture-handler.
Sure, let me clarify š . I managed to get pinch-to-zoom as well as rotate-with-two-fingers to work simultaneously, but the user can't drag/pan the image while doing the other two. The apps I mentioned (Snapchat, Messenger stories) exemplify how I think the UX should be - if the user touches the image with two fingers, he/she should be able to mutate the image on all params simultaneously (pan, zoom, rotate).
I've made a snack of the rendering issue here
from react-native-gesture-handler.
Made it work with all three gesture handlers - should have read the docs more carefully, as it clearly says that I can use an array for simultaneousHandlers
I've posted a snack here of the sticker. It's still a WIP, as I still need to figure out how to handle the rendering issue mentioned above, as well as use the native driver.
Any feedback/input is much appreciated
https://snack.expo.io/@jhalborg/sticker-example
from react-native-gesture-handler.
Great work @jhalborg ! Happy you managed to get it to work. Have you managed to validate if the rendering issue is related to gesture handler or maybe it is some problem with using transforms in react native (I suggested that you start timing Animation on one of these properties instead of connecting it to handler). If that is the case can you please close this issue?
from react-native-gesture-handler.
@jhalborg Just tried your snack on an iPhone 7+ 11.1.2 and it seems to work perfectly. No rendering issues at all. Are you testing on an Android?
from react-native-gesture-handler.
Thanks @zachgibson for trying this out.
@jhalborg can you share what simulator/device/iOS version are you seeing this on? I'm quite confident this visual issue isn't related to gesture handler library but you never know...
from react-native-gesture-handler.
@kmagiera No problem man. Iām really excited about react-native-gesture-handler so I want to try and help out any way I can.
from react-native-gesture-handler.
Closing this for now @jhalborg
If you happen to have some time to revisit and give us an update feel free to reopen
from react-native-gesture-handler.
@zachgibson @kmagiera - Thanks for investigating, and sorry for being so late with the response. I've finally been allotted some more time to doing the sticker-thing, so I'm back on issue now :-)
I can't reproduce the tearing anymore, so it must have been some environment anomaly.
I think I now have something that's a passable experience for the user, except for two remaining issues
Initial placement
I've tried modifying the initial placement of the sticker component on the screen by setting the following in the constructor:
const INITIAL_X_TRANSLATION = 0;
const INITIAL_Y_TRANSLATION = -200;
const INITIAL_LAST_OFFSET = { x: INITIAL_X_TRANSLATION, y: INITIAL_Y_TRANSLATION };
this.translateX = new Animated.Value(INITIAL_X_TRANSLATION);
this.translateY = new Animated.Value(INITIAL_Y_TRANSLATION);
this.lastOffset = INITIAL_LAST_OFFSET;
This works fine on first draw, but the sticker jumps on first drag. On subsequent drags, everything is fine, and it jumps back to the 'expected' position after first release. I can't seem to find a solution to this, maybe one of you can help?
Using native driver
@kmagiera, you mentioned in another issue that in order to use native driver on nested gesture handlers, I should just add an Animated.View
between each handler. I can't get this to work, it seems. In my current code, the sticker component simply disappears. Do you have a working example somewhere?
I've created a snack here, but perhaps it's more of a gist seeing as Snack seems to have problems importing this very lib at the moment.
I'd love some feedback/help :-)
EDIT: In relation to the first issue, suggestions on how to implement a "Reset position" button would also be welcome - It doesn't seem that a simple setValue
works for me.
from react-native-gesture-handler.
So, I figured out a fix for initial placement, but using a different approach - JSX instead of animated coords.
Before, I had:
<View style={{ overflow: 'hidden' }} >
<Image
source={{
uri: chosenImage.uri,
}}
style={{
height: imageSize,
width: imageSize,
}}
>
<Sticker watermarkUrl={this.props.watermarkUrl} />
</Image>
</View>
But placement can instead be done by using the ImageBackground
component:
<View style={{ overflow: 'hidden' }} >
<ImageBackground
source={{
uri: chosenImage.uri,
}}
style={{
height: imageSize,
width: imageSize,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Sticker watermarkUrl={this.props.watermarkUrl} />
</ImageBackground>
</View>
This does not solve the reset button use case, though
from react-native-gesture-handler.
I'm wondering about this in the code: if (event.nativeEvent.oldState === State.ACTIVE)
Wouldn't event.nativeEvent.oldState
would be undefined as it's not being declared?
from react-native-gesture-handler.
@jhalborg
Hi, I'm a little late, but I was wondering if there's a way to solve the pinch, in this case, when I try to enlarge the sticker more, it goes back to its original size and then it starts to expand
(My english is in work progress)
from react-native-gesture-handler.
Related Issues (20)
- Expo app crashes when using GestureDetector HOT 9
- TurboModuleRegistry.getEnforcing(...): 'RNGestureHandlerModule' could not be found HOT 12
- Unable to resolve "./TouchableNativeFeedback" from "node_modules/react-native-gesture-handler/src/components/touchables/index.ts" HOT 1
- Some performance issues when combining FlatList, react-native-gesture-handler, and react-native-reanimated HOT 1
- Privacy Info HOT 4
- Touchables do not register taps in nested FlatList on iOS
- Combining Pan Gesture and Swipeable creates unexpected behavior HOT 4
- [Web] Nested Pressable inside a Swipeable captures press when swiping
- Improve Gradle build by declaring output HOT 2
- manualActivation doesn't work in the Web. HOT 6
- Pan gesture always runs simultaneously with the PagerView
- Event callback is not running in ui thread. HOT 2
- Pan gesture with manual activation disables responding of any touchable in the app
- `isFormsStackingContext(node)` does not have NativeState on react-native 0.73 HOT 3
- Certain classes (ScrollView, RNGHTextInput) no longer exporting type HOT 6
- Gesture.Pan() causing excessive re-renders (too slow) HOT 2
- Build error: "2 files found with path 'lib/arm64-v8a/libjsi.so" HOT 4
- `RectButton`, `BorderlessButton` and `BaseButton` don't have support for View ref methods
- WEB/NATIVE inconsistent behaviour of pan gesture callbacks with manual activation. HOT 1
- New architecture crashes on React Native < 0.74 (`Assertion failed: (hasNativeState<T>(runtime))`) HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
š Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ššš
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ā¤ļø Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-native-gesture-handler.