@@ -33,4 +33,32 @@
|
||||
self.layer.borderWidth = selected ? 2.0 : 0;
|
||||
}
|
||||
|
||||
- (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated
|
||||
{
|
||||
[super setDragState:dragState animated:NO];
|
||||
|
||||
switch (dragState) {
|
||||
case MGLAnnotationViewDragStateNone:
|
||||
break;
|
||||
case MGLAnnotationViewDragStateStarting: {
|
||||
[UIView animateWithDuration:.4 delay:0 usingSpringWithDamping:.4 initialSpringVelocity:.5 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 2, 2);
|
||||
} completion:nil];
|
||||
break;
|
||||
}
|
||||
case MGLAnnotationViewDragStateDragging:
|
||||
break;
|
||||
case MGLAnnotationViewDragStateCanceling:
|
||||
break;
|
||||
case MGLAnnotationViewDragStateEnding: {
|
||||
[UIView animateWithDuration:.4 delay:0 usingSpringWithDamping:.4 initialSpringVelocity:.5 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
|
||||
} completion:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -411,6 +411,7 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
|
||||
{
|
||||
if (longPress.state == UIGestureRecognizerStateBegan)
|
||||
{
|
||||
/*
|
||||
CGPoint point = [longPress locationInView:longPress.view];
|
||||
NSArray *features = [self.mapView visibleFeaturesAtPoint:point];
|
||||
NSString *title;
|
||||
@@ -427,6 +428,7 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
|
||||
pin.subtitle = [[[MGLCoordinateFormatter alloc] init] stringFromCoordinate:pin.coordinate];
|
||||
// Calling `addAnnotation:` on mapView is not required since `selectAnnotation:animated` has the side effect of adding the annotation if required
|
||||
[self.mapView selectAnnotation:pin animated:YES];
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +592,12 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
|
||||
// uncomment to flatten the annotation view against the map when the map is tilted
|
||||
// this currently causes severe performance issues when more than 2k annotations are visible
|
||||
// annotationView.flat = YES;
|
||||
|
||||
// uncomment to make the annotation view draggable
|
||||
// also note that having two long press gesture recognizers on overlapping views (`self.view` & `annotationView`) will cause weird behaviour
|
||||
// comment out the pin dropping functionality in the handleLongPress: method in this class to make draggable annotation views play nice
|
||||
annotationView.draggable = YES;
|
||||
|
||||
|
||||
// uncomment to force annotation view to maintain a constant size when the map is tilted
|
||||
// by default, annotation views will shrink and grow as the move towards and away from the
|
||||
@@ -603,6 +611,12 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
|
||||
return annotationView;
|
||||
}
|
||||
|
||||
- (void)mapView:(MGLMapView *)mapView didDragAnnotationView:(nonnull MGLAnnotationView *)annotationView toCoordinate:(CLLocationCoordinate2D)coordinate
|
||||
{
|
||||
MGLPointAnnotation *annotation = (MGLPointAnnotation *)annotationView.annotation;
|
||||
annotation.coordinate = coordinate;
|
||||
}
|
||||
|
||||
- (BOOL)mapView:(__unused MGLMapView *)mapView annotationCanShowCallout:(__unused id <MGLAnnotation>)annotation
|
||||
{
|
||||
return YES;
|
||||
|
||||
@@ -6,6 +6,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol MGLAnnotation;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
|
||||
MGLAnnotationViewDragStateNone = 0, // View is sitting on the map.
|
||||
MGLAnnotationViewDragStateStarting, // View is beginning to drag.
|
||||
MGLAnnotationViewDragStateDragging, // View is being dragged.
|
||||
MGLAnnotationViewDragStateCanceling, // View dragging was cancelled and will be returned to its starting positon.
|
||||
MGLAnnotationViewDragStateEnding // View was dragged.
|
||||
};
|
||||
|
||||
/** 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
|
||||
|
||||
@@ -69,6 +77,25 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nonatomic, assign, getter=isEnabled) BOOL enabled;
|
||||
|
||||
/**
|
||||
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. `-mapView:didDragAnnotationView:toCoordinate:` will be called when a view is dropped.
|
||||
*/
|
||||
@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;
|
||||
|
||||
/**
|
||||
Called when the `dragState` changes.
|
||||
|
||||
Implementer may override this method in order to customize animations in subclasses.
|
||||
*/
|
||||
- (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Setting this property to YES will cause the annotation view to shrink as it approaches the horizon and grow as it moves away from the
|
||||
horizon when the associated map view is tilted. Conversely, setting this property to NO will ensure that the annotation view maintains
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
#import "MGLAnnotationView.h"
|
||||
#import "MGLAnnotationView_Private.h"
|
||||
#import "MGLAnnotation.h"
|
||||
#import "MGLMapView_Internal.h"
|
||||
|
||||
#import "NSBundle+MGLAdditions.h"
|
||||
|
||||
#include <mbgl/util/constants.hpp>
|
||||
|
||||
@interface MGLAnnotationView ()
|
||||
@interface MGLAnnotationView () <UIGestureRecognizerDelegate>
|
||||
|
||||
@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
|
||||
@property (nonatomic, readwrite, nullable) id <MGLAnnotation> annotation;
|
||||
@property (nonatomic, weak) UIPanGestureRecognizer *panGestureRecognizer;
|
||||
@property (nonatomic, weak) UILongPressGestureRecognizer *longPressRecognizer;
|
||||
@property (nonatomic, weak) MGLMapView *mapView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -62,6 +66,11 @@
|
||||
|
||||
[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];
|
||||
@@ -108,6 +117,129 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Draggable
|
||||
|
||||
- (void)setDraggable:(BOOL)draggable
|
||||
{
|
||||
[self willChangeValueForKey:@"draggable"];
|
||||
_draggable = draggable;
|
||||
[self didChangeValueForKey:@"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
|
||||
{
|
||||
switch (sender.state) {
|
||||
case UIGestureRecognizerStateBegan:
|
||||
self.dragState = MGLAnnotationViewDragStateStarting;
|
||||
break;
|
||||
case UIGestureRecognizerStateChanged:
|
||||
self.dragState = MGLAnnotationViewDragStateDragging;
|
||||
break;
|
||||
case UIGestureRecognizerStateCancelled:
|
||||
self.dragState = MGLAnnotationViewDragStateCanceling;
|
||||
break;
|
||||
case UIGestureRecognizerStateEnded:
|
||||
self.dragState = MGLAnnotationViewDragStateEnding;
|
||||
break;
|
||||
case UIGestureRecognizerStateFailed:
|
||||
self.dragState = MGLAnnotationViewDragStateNone;
|
||||
break;
|
||||
case UIGestureRecognizerStatePossible:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
[self willChangeValueForKey:@"dragState"];
|
||||
_dragState = dragState;
|
||||
[self didChangeValueForKey:@"dragState"];
|
||||
|
||||
if (dragState == MGLAnnotationViewDragStateStarting)
|
||||
{
|
||||
[self.superview bringSubviewToFront:self];
|
||||
}
|
||||
|
||||
if (dragState == MGLAnnotationViewDragStateEnding)
|
||||
{
|
||||
if ([self.mapView.delegate respondsToSelector:@selector(mapView:didDragAnnotationView:toCoordinate:)])
|
||||
{
|
||||
CGPoint offsetAdjustedCenter = self.center;
|
||||
offsetAdjustedCenter.x -= self.centerOffset.dx;
|
||||
offsetAdjustedCenter.y -= self.centerOffset.dy;
|
||||
|
||||
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:offsetAdjustedCenter toCoordinateFromView:self.mapView];
|
||||
[self.mapView.delegate mapView:self.mapView didDragAnnotationView:self toCoordinate:coordinate];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (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.
|
||||
@@ -157,4 +289,4 @@
|
||||
[self.superview accessibilityDecrement];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MGLMapView;
|
||||
|
||||
@interface MGLAnnotationView (Private)
|
||||
|
||||
@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
|
||||
@property (nonatomic, readwrite, nullable) id <MGLAnnotation> annotation;
|
||||
@property (nonatomic, weak) MGLMapView *mapView;
|
||||
|
||||
- (void)setCenter:(CGPoint)center pitch:(CGFloat)pitch;
|
||||
|
||||
|
||||
@@ -4542,7 +4542,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
|
||||
CGPoint center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self];
|
||||
[annotationView setCenter:center pitch:self.camera.pitch];
|
||||
|
||||
annotationView.mapView = self;
|
||||
annotationContext.annotationView = annotationView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,6 +300,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotationView:(MGLAnnotationView *)annotationView;
|
||||
|
||||
/**
|
||||
Tells the delegate that one if its annotation views was dragged to a new coordinate.
|
||||
|
||||
In order to make the new location persistent, you have to update the `coordinate` property of the associated annotation.
|
||||
|
||||
@param mapView The map view containing the annotation view.
|
||||
@param annotationView The annotation view that was dragged.
|
||||
@param coordinate The coordinate that the annotation view was dropped on.
|
||||
|
||||
*/
|
||||
- (void)mapView:(MGLMapView *)mapView didDragAnnotationView:(MGLAnnotationView *)annotationView toCoordinate:(CLLocationCoordinate2D)coordinate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
Reference in New Issue
Block a user