使用自动布局缩放UIScrollView

我试图使用自动布局来实现一个UIScrollView的新方法 。 我已经从内部视图设置约束到滚动视图,以便它可以自动计算自己的contentSize ,这就像一个魅力 – 除了当我试图放大或缩小时,所有的地狱崩溃。 我甚至不能正确地描述发生了什么,除了说内心的看法“搞砸了”之外。

你可以在这里看到这个行为的例子(不是我的项目;你必须设置滚动视图的maximumZoomScale缩放maximumZoomScale和实现-viewForZoomingInScrollView:在缩放将工作)。

有没有其他人遇到这种行为? 目前有什么办法可以缩放UIScrollView来处理自动布局,而不必自己重新实现缩放行为?

我看到的最好的答案是马克的( https://stackoverflow.com/users/1051919/mark-kryzhanouski ),张贴在这里: UIScrollView缩放不适用于Autolayout 。

问题的关键在于,您必须将嵌套在滚动视图中的图像视图锚定到滚动视图的父级。 尽pipe在iOS 6发行说明中提供了指导,但对于我而言,哪些观点“浮动”在什么上并不直观。 在这种情况下,滚动视图只是一个图像视图。

我做了很多实验,希望find一个全IB的方法,没有发现。 您仍然可以在IB中生成视图层次结构,但是仍然需要以编程方式添加约束。 您可以删除部分或全部默认约束(主要是为了解决约束冲突的警告),但是您始终需要使用Mark的代码将图像视图绑定到图像视图的父 – 父视图。

它似乎应该比这更简单 – 它“应该只是工作”,但是:

 NSDictionary *viewsDictionary = @{ @"scrollView": self.scrollView, @"imageView": self.imageView }; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[imageView(width)]" options:0 metrics:@{@"width": @(self.imageView.image.size.width)} views:viewsDictionary]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView(height)]" options:0 metrics:@{@"height": @(self.imageView.image.size.height)} views:viewsDictionary]]; 

没有在故事板中添加imageView,我发现以下作品完美:

 -(UIImageView *)imageView { if (!_imageView) _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; return _imageView; } - (void)viewDidLoad { [super viewDidLoad]; [self.scrollView addSubview:self.imageView]; // Set the min and max: self.scrollView.minimumZoomScale = 0.2; self.scrollView.maximumZoomScale = 5.0; self.scrollView.delegate = self; // Set the content: self.scrollView.zoomScale = 1.0; // reset zoomScale for new image self.scrollView.contentSize = CGSizeMake(image.size.width/2, image.size.height/2); self.imageView.frame = CGRectMake(0, 0, image.size.width/2, image.size.height/2); self.imageView.image = image; } -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.imageView; } 

完整的Swift游乐场示例

我能想到的最简单的例子是将UIImageView添加到UIScrollView 。 这是100%的代码,你只需要添加一个PNG到游乐场。 我叫我的Image.png 。 在Playground中,您将看到“Live View”中呈现的整个事物。 捏放大使用按住Ctrl单击将一个手指放在屏幕上,然后拖动。 直到内容放大比屏幕平移不能工作。 双击图像以在1x和3x比例之间切换。

基于Apple的技术说明TN2154:UIScrollView和Autolayout

疑难杂症

如果你的内容不大于屏幕尺寸,你会发现整个事情非常令人沮丧。 如果你的内容完全适合屏幕上,什么都不会发生。 这就是为什么你必须变焦才能工作。 如果你想向自己certificate它是有效的,那么testing一个非常大的图像(比窗口大)。

 import UIKit import PlaygroundSupport enum TapToggle { case Regular, Large } class ScrollingViewController : UIViewController { var tapToggle: TapToggle = .Large var scrollView: UIScrollView? var imageView: UIImageView? override func viewDidLoad() { let image = UIImage(named: "Image") let imageView = UIImageView(image: image) imageView.translatesAutoresizingMaskIntoConstraints = false imageView.backgroundColor = .white imageView.isUserInteractionEnabled = true let scrollView = UIScrollView() scrollView.minimumZoomScale = 0.5 scrollView.maximumZoomScale = 10.0 scrollView.delegate = self scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(imageView) let imageViewKey = "imageView" let imageViews = [imageViewKey: imageView] scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(imageViewKey)]|", options: [], metrics: nil, views: imageViews)) scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(imageViewKey)]|", options: [], metrics: nil, views: imageViews)) self.imageView = imageView scrollView.backgroundColor = .white self.view.addSubview(scrollView) let scrollViewKey = "scrollView" let scrollViews = [scrollViewKey: scrollView] self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(scrollViewKey)]|", options: [], metrics: nil, views: scrollViews)) self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(scrollViewKey)]|", options: [], metrics: nil, views: scrollViews)) self.scrollView = scrollView let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap(sender:))) tapGesture.numberOfTapsRequired = 2 self.imageView?.addGestureRecognizer(tapGesture) } @objc public func didDoubleTap(sender: AnyObject) { switch self.tapToggle { case .Regular: self.scrollView?.zoomScale = 1.0 self.tapToggle = .Large case .Large: self.scrollView?.zoomScale = 3.0 self.tapToggle = .Regular } } } extension ScrollingViewController: UIScrollViewDelegate { func viewForZooming(in scrollView: UIScrollView) -> UIView? { return self.imageView } func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) { print("\(scale)") } } PlaygroundPage.current.needsIndefiniteExecution = true PlaygroundPage.current.liveView = ScrollingViewController()