UIScrollView-自定义地图-防止地图上的标记子视图与地图一起缩放



我有一个有限区域的自定义地图,并将其设置为正确显示用户的位置。这张地图是一张1600像素的正方形图像,位于UIScrollView中。

我有一个十字线图像来显示用户的当前位置,缩放比例1.0是所需的大小。当我捏缩放滚动视图时,十字线会随之缩放。我希望子视图在屏幕上保持不变。

我找不到任何关于这方面的信息,最好的方法是什么?

如果我能为你提供什么帮助,请告诉我。

非常感谢!

编辑-

进一步研究后,我尝试使用一个UIScrollViewDelegate方法- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale来获取标记的当前中心和大小,然后进行调整,但这只会在缩放结束时缩放。我更希望在用户缩放时标记保持不变。

编辑2-

Cake在下面提供了一个很好的答案,但我还没能像我想象的那样实现它

我将UIImageView作为占位符,alpha设置为0。此占位符相对于地图移动以显示用户位置。这是我所期望的操作。不幸的是,它会随着地图而调整大小,因为它是地图的子视图(所以它保持不变(。

根据Cake下面的答案,我创建了非缩放十字线图像,并将其作为同级子视图添加到滚动视图中。一旦Cake指出了这些问题,数学计算就非常简单,可以得到十字准线的新框架:

    CGPoint ULPC = userLocationPlaceholder.center;
    float zs = scrollView.zoomScale;
    CGRect newFrame = CGRectMake(((ULPC.x * zs) - scrollView.contentOffset.x) - 20, ((ULPC.y * zs) - scrollView.contentOffset.y) - 20, 40, 40);

图像宽度为40点。这与中锋完美匹配。

现在遇到的问题是,我无法将十字线图像锁定到占位符。

我已经尝试过使用这样的自调用动画:

-(void)animeUserLocationAttachment
{
[UIView animateWithDuration:0.05 
                      delay:0 
                    options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear )
                 animations:^{
                     userLocationDotContainer.frame = newFrame;
               } completion:^(BOOL finished){
                     // Call self
                     [self animateUserLocationAttachment];
                 }];
}

当我开始滚动/缩放时,这会锁定动画,使十字线保持原位,直到我释放滚动/缩放,然后它会正确更新它的位置。

有什么办法可以绕过这一点,或者我可以应用其他方法吗?

非常感谢

编辑3-

我重新接受了Cake的回答,因为它涵盖了90%的问题。除了他的回答之外,我还实现了ScrollViewDelegate方法scrollViewWillBeginDragging:scrollViewWillBeginDecelerating:来缩放占位符以匹配相对于地图的十字线的当前大小,显示占位符(即地图图像的子视图(并隐藏十字线图像。委托方法scrollviewWillBeginZooming:withView:不显示占位符,因为它随映射而缩放。正如Cake所推荐的,我将为本期提出一个新问题。

对应的方法(scrollViewDidEndZooming:withView:atScale:scrollViewDidEndDragging:willDecelerate:和-scollViewDidEndDecelerating:`(都隐藏占位符,并重新显示十字线。

这个问题很老,但对于未来类似的问题,我最近利用另一篇文章中Andrew Madsen的提示解决了一个类似的问题

我有一个UIScrollView,里面有一个UI图像视图。在UIImageView的附件中,我有很多MKAnnotationView(这些是我的子视图,我不想用超视图缩放(。

我做了UIImageView的子类,并实现了setTransform:方法,如下所示:

#import "SLImageView.h"
@implementation SLImageView

    - (void)setTransform:(CGAffineTransform)transform
    {
        [super setTransform:transform];
        CGAffineTransform invertedTransform = CGAffineTransformInvert(transform);
        for (id obj in self.subviews)
        {
            if ([obj isKindOfClass:[MKAnnotationView class]])
            {
                [((UIView *)obj) setTransform:invertedTransform]; 
            }
        }
    }
    @end

这非常有效!米克。

创建与包含滚动视图的视图或视图控制器关联的另一个十字线图像。然后让这个始终捕捉到你已经拥有的十字线图像的中心。然后,隐藏原始十字线图像。然后,您可以避免滚动视图缩放已解除关联的十字线,并且它应该保持相同的大小。

相对坐标系

可可触摸中的每个视图都有一个具有原点的框架属性。为了使一个视图所拥有的对象相对于另一个视图正确定位,您所要做的就是找出它们起源的差异。如果一个视图是另一个视图的子视图,那么这并不太难。

  • 获取容器视图的原点
  • 获取子视图在容器视图中的位置
  • 获取子视图的原点
  • 计算原点位置的差异
  • 获取要重叠的对象的位置(相对于子视图(
  • 计算要重叠的对象相对于容器视图的位置
  • 将十字准线移动到此位置

Swift等价于Mick的答案:

class MapContainerView:UIView {
    @IBOutlet var nonScalingViews: [UIView]!
    override var transform: CGAffineTransform {
        didSet {
            guard let nonScalingViews = nonScalingViews else {
                return
            }
            let invertedTransform = CGAffineTransformInvert(transform)
            for view in nonScalingViews {
                view.transform = invertedTransform
            }
        }
    }
}

最新更新