关键在于,您必须将嵌套在滚动视图中的图像视图锚定到滚动视图的父级。尽管iOS 6发行说明提供了指导,但我认为哪个视图“浮动”在哪个视图上并不直观。 在这种情况下,滚动视图只是一个单独的图像视图。
我确实进行了很多尝试,希望找到全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]];
在Storyboard中没有添加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;
}
contentSize
而不是用自动布局约束,这也是问题的重点。请查看我发布的第一个链接,其中有对我所说内容的描述(搜索“Pure Auto Layout approach”短语)。 - phu我能想到的最简单的示例是将 UIImageView
添加到 UIScrollView
中。这是100%的代码,您只需要向 Playground 添加一个 PNG 图像。我把我的命名为 Image.png
。在 Playground 中,您将在“实时视图”中看到整个内容呈现。使用 Ctrl + 单击来放大缩小,然后拖动屏幕。在内容被放大到比屏幕更大之前,平移不起作用。双击图像可在1x和3x缩放之间切换。
基于苹果公司的技术笔记 TN2154:UIScrollView 和 Autolayout
如果您的内容不大于屏幕大小,您会发现整个过程非常令人沮丧。如果您的内容完全适合屏幕,则不会发生任何事情。这就是为什么您也必须使缩放工作。如果您想证明它有效,请使用真正大的图像(比窗口大)进行测试。
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()
scrollViewWillBeginZooming:withView:
中删除约束,在scrollViewDidEndZooming:withView:atScale:
中重新添加约束,在缩放期间它运行得更好,但缩放后内容位置不正确。 - devguydavid