-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[ios] [WiP] #5036 draggable annotation views #5272
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,14 @@ | |
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) { | ||
| MGLAnnotationViewDragStateNone = 0, // View is sitting on the map | ||
| MGLAnnotationViewDragStateStarting, // View is beginning to drag and animation starts | ||
| MGLAnnotationViewDragStateDragging, // View is being dragged | ||
| MGLAnnotationViewDragStateCanceling, // View dragging was cancelled and will be returned to its starting positon. | ||
| MGLAnnotationViewDragStateEnding // View was dragged, new coordinate has been set and stop animation is finishing | ||
| }; | ||
|
|
||
| /** The MGLAnnotationView class is responsible for representing point-based annotation markers as a view. Annotation views represent an annotation object, which is an object that corresponds to the MGLAnnotation protocol. When an annotation’s coordinate point is visible on the map view, the map view delegate is asked to provide a corresponding annotation view. If an annotation view is created with a reuse identifier, the map view may recycle the view when it goes offscreen. */ | ||
| @interface MGLAnnotationView : UIView | ||
|
|
||
|
|
@@ -48,6 +56,23 @@ NS_ASSUME_NONNULL_BEGIN | |
| */ | ||
| @property (nonatomic, assign, getter=isScaledWithViewingDistance) BOOL scalesWithViewingDistance; | ||
|
|
||
| /** | ||
| Setting this property to YES will make the view draggable. Long press followed by a pan gesture will start to move the | ||
| view around the map. Each update will center the annotation view. setCoordinate: is called on the associated annotation when panning ends successfully. | ||
| */ | ||
| @property (nonatomic, assign, getter=isDraggable) BOOL draggable; | ||
|
|
||
| /** | ||
| All states are handled automatically when `draggable` is set to YES. | ||
| Custom animations can be achieved by overriding setDragState:animated: | ||
| */ | ||
| @property (nonatomic, readonly) MGLAnnotationViewDragState dragState; | ||
|
|
||
| /** | ||
| Implementer may override this method to use a custom animation for the different MGLAnnotationViewDragState. | ||
| */ | ||
| - (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated __attribute__((objc_requires_super)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: use |
||
|
|
||
| /** | ||
| Called when the view is removed from the reuse queue. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,10 +6,13 @@ | |
|
|
||
| #include <mbgl/util/constants.hpp> | ||
|
|
||
| @interface MGLAnnotationView () | ||
| @interface MGLAnnotationView () <UIGestureRecognizerDelegate> | ||
|
|
||
| @property (nonatomic) id<MGLAnnotation> annotation; | ||
| @property (nonatomic, readwrite, nullable) NSString *reuseIdentifier; | ||
| @property (nonatomic, weak) UIPanGestureRecognizer *panGestureRecognizer; | ||
| @property (nonatomic, weak) UILongPressGestureRecognizer *longPressRecognizer; | ||
| @property (nonatomic, weak) MGLMapView *mapView; | ||
|
|
||
| @end | ||
|
|
||
|
|
@@ -49,6 +52,11 @@ - (void)setCenter:(CGPoint)center pitch:(CGFloat)pitch | |
|
|
||
| [super setCenter:center]; | ||
|
|
||
| // Omit applying a new transformation while the view is being dragged. | ||
| if (self.dragState == MGLAnnotationViewDragStateDragging) { | ||
| return; | ||
| } | ||
|
|
||
| if (self.flat) | ||
| { | ||
| [self updatePitch:pitch]; | ||
|
|
@@ -95,6 +103,129 @@ - (void)updateScaleForPitch:(CGFloat)pitch | |
| } | ||
| } | ||
|
|
||
| - (void)setDraggable:(BOOL)draggable | ||
| { | ||
| _draggable = draggable; | ||
| if (draggable) { | ||
| [self enableDrag]; | ||
| } else { | ||
| [self disableDrag]; | ||
| } | ||
| } | ||
|
|
||
| - (void)enableDrag | ||
| { | ||
| if (!_longPressRecognizer) { | ||
| UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; | ||
| recognizer.delegate = self; | ||
| [self addGestureRecognizer:recognizer]; | ||
| _longPressRecognizer = recognizer; | ||
| } | ||
|
|
||
| if (!_panGestureRecognizer) { | ||
| UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; | ||
| recognizer.delegate = self; | ||
| [self addGestureRecognizer:recognizer]; | ||
| _panGestureRecognizer = recognizer; | ||
| } | ||
| } | ||
|
|
||
| - (void)disableDrag | ||
| { | ||
| [self removeGestureRecognizer:_longPressRecognizer]; | ||
| [self removeGestureRecognizer:_panGestureRecognizer]; | ||
| } | ||
|
|
||
| - (void)handleLongPress:(UILongPressGestureRecognizer *)sender | ||
| { | ||
| if (sender.state == UIGestureRecognizerStateBegan) | ||
| { | ||
| self.dragState = MGLAnnotationViewDragStateStarting; | ||
| } | ||
| else if (sender.state == UIGestureRecognizerStateChanged) | ||
| { | ||
| self.dragState = MGLAnnotationViewDragStateDragging; | ||
| } | ||
| else if (sender.state == UIGestureRecognizerStateCancelled) { | ||
| self.dragState = MGLAnnotationViewDragStateCanceling; | ||
| } | ||
| else if (sender.state == UIGestureRecognizerStateEnded) | ||
| { | ||
| self.dragState = MGLAnnotationViewDragStateEnding; | ||
| } | ||
| } | ||
|
|
||
| - (void)handlePan:(UIPanGestureRecognizer *)sender | ||
| { | ||
| CGPoint center = [sender locationInView:sender.view.superview]; | ||
| [self setCenter:center pitch:self.mapView.camera.pitch]; | ||
|
|
||
| if (sender.state == UIGestureRecognizerStateEnded) { | ||
| self.dragState = MGLAnnotationViewDragStateNone; | ||
| } | ||
| } | ||
|
|
||
| - (void)setDragState:(MGLAnnotationViewDragState)dragState | ||
| { | ||
| [self setDragState:dragState animated:YES]; | ||
| } | ||
|
|
||
| - (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated | ||
| { | ||
| _dragState = dragState; | ||
|
|
||
| switch (dragState) { | ||
| case MGLAnnotationViewDragStateNone: | ||
| break; | ||
| case MGLAnnotationViewDragStateStarting: { | ||
| if (animated) | ||
| { | ||
| [UIView animateWithDuration:.20 animations:^{ | ||
| self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 2, 2); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are absolutely right @1ec5 the animation stuff should not be included in |
||
| }]; | ||
| } | ||
| break; | ||
| } | ||
| case MGLAnnotationViewDragStateDragging: | ||
| break; | ||
| case MGLAnnotationViewDragStateCanceling: | ||
| break; | ||
| case MGLAnnotationViewDragStateEnding: { | ||
|
|
||
| CLLocationCoordinate2D coord = [self.mapView convertPoint:self.center toCoordinateFromView:self.mapView]; | ||
| [self.annotation setCoordinate:coord]; | ||
|
|
||
| if (animated) | ||
| { | ||
| [UIView animateWithDuration:.20 animations:^{ | ||
| self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1); | ||
| } completion:^(BOOL finished) { | ||
| self.dragState = MGLAnnotationViewDragStateNone; | ||
| }]; | ||
| } | ||
| else | ||
| { | ||
| _dragState = MGLAnnotationViewDragStateNone; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer | ||
| { | ||
| BOOL isDragging = self.dragState == MGLAnnotationViewDragStateDragging; | ||
| if ([gestureRecognizer isKindOfClass:UIPanGestureRecognizer.class] && !(isDragging)) { | ||
| return NO; | ||
| } | ||
| return YES; | ||
| } | ||
|
|
||
| - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer | ||
| { | ||
| return YES; | ||
| } | ||
|
|
||
| - (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event | ||
| { | ||
| // Allow mbgl to drive animation of this view’s bounds. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all
MGLAnnotationimplementations allow forcoordinateto be changed, so we’ve been making this mutable only as necessary.