【问题标题】:Moving MKCircle on MKMapview and dragging MKMapview在 MKMapview 上移动 MKCircle 并拖动 MKMapview
【发布时间】:2018-08-21 20:59:02
【问题描述】:

我在 MKMapView 上有一个 MKCircle。它是用户可拖动的,但如果用户将区域拖动到圆圈外,则地图应该会移动。

- (IBAction)createPanGestureRecognizer:(id)sender
{
    _mapView.scrollEnabled=NO;
    _panRecognizer = [[UIPanGestureRecognizer alloc]
                      initWithTarget:self action:@selector(respondToPanGesture:)];
    [_mapView addGestureRecognizer:_panRecognizer];
}

-(void)respondToPanGesture:(UIPanGestureRecognizer*)sender {

    static CGPoint originalPoint;

    if (sender.state == UIGestureRecognizerStateBegan) {
        CGPoint point = [sender locationInView:_mapView];
        CLLocationCoordinate2D tapCoordinate = [_mapView convertPoint:point toCoordinateFromView:_mapView];

        CLLocation *tapLocation = [[CLLocation alloc] initWithLatitude:tapCoordinate.latitude longitude:tapCoordinate.longitude];

        CLLocationCoordinate2D originalCoordinate = [_circle coordinate];
        CLLocation *originalLocation = [[CLLocation alloc] initWithLatitude:originalCoordinate.latitude longitude:originalCoordinate.longitude];

        if ([tapLocation distanceFromLocation:originalLocation] > [_circle radius]) {
            _mapView.scrollEnabled=YES;
            _isAllowedToMove=NO;
        }
        else if ([tapLocation distanceFromLocation:originalLocation] < [_circle radius]) {
            originalPoint = [_mapView convertCoordinate:originalCoordinate toPointToView:sender.view];
            _isAllowedToMove=YES;
        }
    }

    if (sender.state == UIGestureRecognizerStateChanged) {
        if (_isAllowedToMove)
        {
            CGPoint translation = [sender translationInView:sender.view];
            CGPoint newPoint    = CGPointMake(originalPoint.x + translation.x, originalPoint.y + translation.y);

            CLLocationCoordinate2D newCoordinate = [_mapView convertPoint:newPoint toCoordinateFromView:sender.view];

            MKCircle *circle2 = [MKCircle circleWithCenterCoordinate:newCoordinate radius:[_circle radius]];
            [_mapView addOverlay:circle2];
            [_mapView removeOverlay:_circle];
            _circle = circle2;
        }
    }

    if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) {
        _mapView.scrollEnabled=NO;
        _isAllowedToMove=NO;
    }
}

拖动圆圈可以正常工作,但在尝试拖动地图时,它会保持静止。 我的假设是

_mapView.scrollEnabled=YES;

使地图可拖动,但需要启动另一个拖动手势。 如何在不失去移动圆圈的能力的情况下做到这一点?

【问题讨论】:

    标签: ios mkmapview uipangesturerecognizer mkoverlay


    【解决方案1】:

    使地图可以在用户开始拖到圆圈外时被拖动(并且如果用户开始在圆圈内拖动 ),不要从一开始就禁用scrollEnabled——让它保持打开状态(直到拖动开始我们可以决定是否禁用)。

    为了在初始状态下保持scrollEnabled(即让地图自己平移)添加我们自己的手势识别器,我们需要实现shouldRecognizeSimultaneouslyWithGestureRecognizer并返回@ 987654324@.

    更新后的createPanGestureRecognizer: 如下所示:

    - (IBAction)createPanGestureRecognizer:(id)sender
    {
        //_mapView.scrollEnabled=NO;  // <-- do NOT disable scrolling here
        _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondToPanGesture:)];
        _panRecognizer.delegate = self;  // <-- to implement shouldRecognize
        [_mapView addGestureRecognizer:_panRecognizer];
    }
    
    -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        return YES;
    }
    

    然后在我们的手势处理程序中,当手势开始时,根据平移开始的位置(圆圈外或圆圈内)启用或禁用scrollEnabled

    if ([tapLocation distanceFromLocation:originalLocation] > [_circle radius]) {
        _mapView.scrollEnabled=YES;
        _isAllowedToMove=NO;
    }
    else //if ([tapLocation distanceFromLocation:originalLocation] < [_circle radius]) {
    //NOTE: It's not really necessary to check if distance is less than radius
    //      in the ELSE part since in the IF we checked if it's greater-than.
    //      If we get to the ELSE, we know distance is <= radius.
    //      Unless for some reason you want to handle the case where
    //      distance exactly equals radius differently but this is unlikely.
    {
        originalPoint = [_mapView convertCoordinate:originalCoordinate toPointToView:sender.view];
        _mapView.scrollEnabled=NO;  // <-- disable scrolling HERE
        _isAllowedToMove=YES;
    }
    

    最后,在手势结束时始终重新启用scrollEnabled(以防万一)。
    当下一个手势开始时,必要时会重新禁用:

    if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateFailed || sender.state == UIGestureRecognizerStateCancelled) {
        _mapView.scrollEnabled=YES;  // <-- enable instead of disable
        _isAllowedToMove=NO;
    }
    

    请注意,如果允许用户多次调用createPanGestureRecognizer:,您可能应该将识别器的创建和添加移到其他地方(可能是viewDidLoad),否则会向地图添加多个实例。

    或者,将按钮更改为切换按钮,这样如果“移动”模式开启,它会从地图中移除手势识别器,而不是创建和添加它。

    【讨论】:

    • 谢谢。我正在实现shouldRecognizeSimultaneouslyWithGestureRecognizer 并以数十种方式扭曲代码,但我忘记了像_panRecognizer.delegate = self 这样简单的东西;如果有人想使用该代码,请不要忘记将&lt;UIGestureRecognizerDelegate&gt; 添加到@interface 行的末尾。要添加或删除手势识别器,我使用切换按钮。
    【解决方案2】:

    使用 swift 4

    更新了答案

    包括一些变化: panGesture.maximumNumberOfTouches = 1 避免将捏合缩放为平移手势 用于可以启动平移手势的活动区域的屏幕点。

    private func addPanGestureRecognizer(to map: MKMapView) {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(respondToPanGesture(_:)))
        panGesture.maximumNumberOfTouches = 1
        panGesture.delegate = self
        map.addGestureRecognizer(panGesture)
    }
    
    @objc private func respondToPanGesture(_ sender: UIPanGestureRecognizer) {
        guard let map = self.map else {
            return
        }
    
        let circlePoint = map.convert(startPoint, toPointTo: map) // circle center in View coordinate system
    
        switch sender.state {
        case .began:
            let point = sender.location(in: map)
            // Set touch radius in points (20), not meters to support different map zoom levels
            if point.radiusContainsPoint(radius: 20, point: circlePoint) {
                // set class property to store initial circle position before start dragging
                initialDragPoint = circlePoint
                map.isScrollEnabled = false
                isDragEnabled = true
            }
            else {
                map.isScrollEnabled = true
                isDragEnabled = false
            }
        case .changed:
            if isDragEnabled {
                let translation = sender.translation(in: map)
                let newPoint = CGPoint(x: initialDragPoint.x + translation.x, y: initialDragPoint.y + translation.y)
                let updatedCoordinate = map.convert(newPoint, toCoordinateFrom: map)
                let newOverlay = makeCircleOverlay(at: updatedCoordinate)
                map.remove(circleOverlay)
                map.add(newOverlay)
                circleOverlay = newOverlay
            }
        case .ended, .failed, .cancelled:
            map.isScrollEnabled = true
            isDragEnabled = false
        case .possible:
            break
        }
    }
    
    // MARK: - UIGestureRecognizerDelegate
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      • 2012-08-09
      • 2019-03-22
      • 1970-01-01
      • 2010-11-14
      • 2016-01-16
      相关资源
      最近更新 更多