UIScrollView - 自定义地图 - 使用地图缩放防止地图上的标记子视图

时间:2012-06-22 15:06:19

标签: objective-c uiscrollview zoom subview

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

我有一个十字准线图像来显示用户的当前位置,在zoomScale 1.0处是所需的大小。当我捏合并缩放scrollView时,十字准线会随之缩放。我想让子视图在屏幕上保持相同的大小。

我无法找到关于此的任何信息,最好的方法是什么?

如果我能为您提供帮助,请告知我们。

非常感谢!

编辑 -

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

编辑2 -

Cake在下面提供了一个很好的答案,但我无法以我想象的方式实现这一点。

我将UIImageView作为占位符,alpha设置为0.此占位符相对于地图移动以显示用户位置。这正如我所期望的那样运作。不幸的是,这会根据地图调整大小,因为它是地图的子视图(因此它会保留在原位)。

在下面的回答中,我创建了非缩放十字准线图像,并将其作为兄弟子视图添加到滚动视图中。一旦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:和-scrollViewDidEndDecelerating:`)全部隐藏占位符,并重新显示十字准线。

3 个答案:

答案 0 :(得分:3)

问题是陈旧但是对于未来类似的问题,我最近解决了一个类似的问题,应用了另一个帖子的Andrew Madsen的暗示。

我是一个UIScrollView,里面有一个UIImageView。附加到UIImageView我有很多MKAnnotationView(这些是我不想用superview缩放的子视图)。

我做了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

这完美无缺! 米克。

答案 1 :(得分:2)

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

相对坐标系

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

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

答案 2 :(得分:1)

斯威夫相当于米克的回答:

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
            }
        }
    }
}