diff --git a/PROPS.md b/PROPS.md index 1f57a327..d69ef7f4 100644 --- a/PROPS.md +++ b/PROPS.md @@ -158,6 +158,7 @@ Optional, a function called whenever the user starts or stops dragging the view. * `state` - `start` or `end`, whether the user started or finished dragging. * `x` - The horizontal position of the view (relative to the center). * `y` - The vertical position of the view (relative to the center). +* `targetSnapPointId` - For `end` state, the string `id` of the target point in the `snapPoints` array (assuming it was provided). Otherwise, empty string. #### `onAlert` (function) diff --git a/lib/android/src/main/java/com/wix/interactable/Events.java b/lib/android/src/main/java/com/wix/interactable/Events.java index edd64289..c3f86a58 100644 --- a/lib/android/src/main/java/com/wix/interactable/Events.java +++ b/lib/android/src/main/java/com/wix/interactable/Events.java @@ -80,12 +80,13 @@ public static class onDrag extends Event { WritableMap eventData; - public onDrag(int viewTag, String state, float x, float y) { + public onDrag(int viewTag, String state, float x, float y, String targetSnapPointId) { super(viewTag); eventData = Arguments.createMap(); eventData.putString("state", state); eventData.putDouble("x", PixelUtil.toDIPFromPixel(x)); eventData.putDouble("y", PixelUtil.toDIPFromPixel(y)); + eventData.putString("targetSnapPointId", targetSnapPointId); } @Override @@ -98,4 +99,24 @@ public void dispatch(RCTEventEmitter rctEventEmitter) { rctEventEmitter.receiveEvent(getViewTag(), getEventName(), eventData); } } + + public static class onStop extends Event { + + WritableMap eventData; + + public onStop(int viewTag, float x, float y) { + super(viewTag); + eventData = Arguments.createMap(); + eventData.putDouble("x", PixelUtil.toDIPFromPixel(x)); + eventData.putDouble("y", PixelUtil.toDIPFromPixel(y)); + } + + @Override + public String getEventName() { return "onStop"; } + + @Override + public void dispatch(RCTEventEmitter rctEventEmitter) { + rctEventEmitter.receiveEvent(getViewTag(), getEventName(), eventData); + } + } } diff --git a/lib/android/src/main/java/com/wix/interactable/InteractableView.java b/lib/android/src/main/java/com/wix/interactable/InteractableView.java index 5d262be4..6998ee50 100644 --- a/lib/android/src/main/java/com/wix/interactable/InteractableView.java +++ b/lib/android/src/main/java/com/wix/interactable/InteractableView.java @@ -101,7 +101,8 @@ public void setEventListener(InteractionListener listener) { @Override public void onAnimatorPause() { - + PointF currentPosition = getCurrentPosition(); + listener.onStop(currentPosition.x, currentPosition.y); } @Override @@ -287,7 +288,7 @@ private ReactRootView getReactRoot() { private void startDrag(MotionEvent ev) { PointF currentPosition = getCurrentPosition(); - listener.onDrag("start",currentPosition.x, currentPosition.y); + listener.onDrag("start",currentPosition.x, currentPosition.y, ""); this.dragStartLocation = new PointF(ev.getX(),ev.getY()); this.animator.removeTempBehaviors(); this.animator.setDragging(true); @@ -312,12 +313,12 @@ private void handleEndOfDrag() { if (this.dragWithSprings != null) toss = this.dragWithSprings.toss; PointF currentPosition = getCurrentPosition(); - listener.onDrag("end",currentPosition.x, currentPosition.y); PointF projectedCenter = new PointF(getTranslationX() + toss*velocity.x, getTranslationY() + toss*velocity.y); InteractablePoint snapPoint = InteractablePoint.findClosestPoint(snapPoints,projectedCenter); + listener.onDrag("end",currentPosition.x, currentPosition.y, snapPoint.id); addTempSnapToPointBehavior(snapPoint); addTempBounceBehaviorWithBoundaries(this.boundaries); @@ -557,6 +558,7 @@ public interface InteractionListener { void onSnap(int indexOfSnapPoint, String snapPointId); void onAlert(String alertAreaId, String alertType); void onAnimatedEvent(float x, float y); - void onDrag(String state, float x, float y); + void onDrag(String state, float x, float y, String targetSnapPointId); + void onStop(float x, float y); } } diff --git a/lib/android/src/main/java/com/wix/interactable/InteractableViewManager.java b/lib/android/src/main/java/com/wix/interactable/InteractableViewManager.java index f5ade08f..5c72bae7 100644 --- a/lib/android/src/main/java/com/wix/interactable/InteractableViewManager.java +++ b/lib/android/src/main/java/com/wix/interactable/InteractableViewManager.java @@ -151,6 +151,7 @@ public Map getExportedCustomDirectEventTypeConstants() { .put("onAlert", MapBuilder.of("registrationName", "onAlert")) .put("onAnimatedEvent", MapBuilder.of("registrationName", "onAnimatedEvent")) .put("onDrag", MapBuilder.of("registrationName", "onDrag")) + .put("onStop", MapBuilder.of("registrationName", "onStop")) .build(); } @@ -179,8 +180,13 @@ public void onAnimatedEvent(float x, float y) { } @Override - public void onDrag(String state, float x, float y) { - eventDispatcher.dispatchEvent(new Events.onDrag(interactableView.getId(),state, x, y)); + public void onDrag(String state, float x, float y, String targetSnapPointId) { + eventDispatcher.dispatchEvent(new Events.onDrag(interactableView.getId(),state, x, y, targetSnapPointId)); + } + + @Override + public void onStop(float x, float y) { + eventDispatcher.dispatchEvent(new Events.onStop(interactableView.getId(), x, y)); } } } diff --git a/lib/ios/Interactable/InteractableView.m b/lib/ios/Interactable/InteractableView.m index 0e613237..2472e07e 100644 --- a/lib/ios/Interactable/InteractableView.m +++ b/lib/ios/Interactable/InteractableView.m @@ -286,7 +286,7 @@ - (void)reportAlertEvent } } -- (void)reportDragEvent:(NSString*)state +- (void)reportDragEvent:(NSString*)state targetSnapPointId:(NSString*)targetSnapPointId { if (self.onDrag) { @@ -294,7 +294,8 @@ - (void)reportDragEvent:(NSString*)state self.onDrag(@{ @"state": state, @"x": @(deltaFromOrigin.x), - @"y": @(deltaFromOrigin.y) + @"y": @(deltaFromOrigin.y), + @"targetSnapPointId":targetSnapPointId }); } } @@ -308,7 +309,7 @@ - (void)handlePan:(UIPanGestureRecognizer *)pan [self cancelCurrentReactTouch]; self.dragStartCenter = self.center; [self setTempBehaviorsForDragStart]; - [self reportDragEvent:@"start"]; + [self reportDragEvent:@"start" targetSnapPointId:@""]; } CGPoint translation = [pan translationInView:self]; @@ -319,8 +320,8 @@ - (void)handlePan:(UIPanGestureRecognizer *)pan pan.state == UIGestureRecognizerStateFailed || pan.state == UIGestureRecognizerStateCancelled) { - [self setTempBehaviorsForDragEnd]; - [self reportDragEvent:@"end"]; + InteractablePoint* point = [self setTempBehaviorsForDragEnd]; + [self reportDragEvent:@"end" targetSnapPointId:point.id]; } } @@ -403,21 +404,22 @@ - (void)setTempBehaviorsForDragStart self.dragBehavior = [self addTempDragBehavior:self.dragWithSpring]; } -- (void)setTempBehaviorsForDragEnd +- (InteractablePoint*)setTempBehaviorsForDragEnd { [self.animator removeTempBehaviors]; self.dragBehavior = nil; - + CGPoint velocity = [self.animator getTargetVelocity:self]; if (self.horizontalOnly) velocity.y = 0; if (self.verticalOnly) velocity.x = 0; CGFloat toss = self.dragToss; CGPoint projectedCenter = CGPointMake(self.center.x + toss*velocity.x, self.center.y + toss*velocity.y); - + InteractablePoint *snapPoint = [InteractablePoint findClosestPoint:self.snapPoints toPoint:projectedCenter withOrigin:self.origin]; if (snapPoint) [self addTempSnapToPointBehavior:snapPoint]; - + [self addTempBounceBehaviorWithBoundaries:self.boundaries]; + return snapPoint; } // MARK: - Behaviors diff --git a/package.json b/package.json index 1a00762e..b9e87fa9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-interactable", - "version": "0.1.3", + "version": "0.1.6", "description": "High performance interactable views in React Native", "license": "MIT", "author": "Tal Kol ", diff --git a/real-life-example/src/RowActions1.js b/real-life-example/src/RowActions1.js index ba4d341f..4b44e216 100644 --- a/real-life-example/src/RowActions1.js +++ b/real-life-example/src/RowActions1.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { StyleSheet, View, Text, Animated, TouchableOpacity, Slider, Dimensions } from 'react-native'; +import { StyleSheet, View, Text, Animated, TouchableOpacity, TouchableHighlight, Slider, Dimensions } from 'react-native'; import Interactable from 'react-native-interactable'; const Screen = Dimensions.get('window'); @@ -80,8 +80,10 @@ class Row extends Component { constructor(props) { super(props); this._deltaX = new Animated.Value(0); + this.state = {isMoving: false, position: 1}; } render() { + const activeOpacity = this.state.position !== 1 ? 0.5 : 1; return ( @@ -152,22 +154,47 @@ class Row extends Component { this.interactableElem = el} horizontalOnly={true} snapPoints={[ {x: 75, damping: 1-this.props.damping, tension: this.props.tension}, {x: 0, damping: 1-this.props.damping, tension: this.props.tension}, {x: -150, damping: 1-this.props.damping, tension: this.props.tension} ]} + onSnap={this.onSnap.bind(this)} + onDrag={this.onDrag.bind(this)} + onStop={this.onStopMoving.bind(this)} dragToss={0.01} animatedValueX={this._deltaX}> - - {this.props.children} - + + + {this.props.children} + + ); } + onSnap({nativeEvent}) { + const { index } = nativeEvent; + this.setState({position: index}); + } + onRowPress() { + const { isMoving, position } = this.state; + if (!isMoving && position !== 1) { + this.interactableElem.snapTo({index: 1}); + } + } + onDrag({nativeEvent}) { + const { state } = nativeEvent; + if (state === 'start') { + this.setState({isMoving: true}); + } + } + onStopMoving() { + this.setState({isMoving: false}); + } onButtonPress(name) { alert(`Button ${name} pressed`); }