UIScrollView使用自动布局进行缩放

时间:2012-12-25 00:41:11

标签: ios uiscrollview zoom autolayout

我正在尝试使用自动布局实现UIScrollView New Way。我已经设置了从内部视图到滚动视图的约束,以便它可以自动计算自己的contentSize,并且它就像一个魅力 - 除了当我尝试放大或缩小时所有的地狱都松散了。我甚至无法正确描述会发生什么,除了说内部视图被“搞砸了”。

您可以看到此行为的示例here(不是我的项目;您必须设置滚动视图的maximumZoomScale并在缩放之前实现-viewForZoomingInScrollView:)。

有没有其他人遇到这种行为?目前是否有办法放大UIScrollView以使用自动布局而无需自己重新实现缩放行为?

3 个答案:

答案 0 :(得分:4)

我见过的最好的答案是马克(https://stackoverflow.com/users/1051919/mark-kryzhanouski),张贴在这里:UIScrollView Zoom Does Not Work With Autolayout

它的关键在于您必须将嵌套在滚动视图中的图像视图锚定到滚动视图的父级。尽管在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]];

答案 1 :(得分:3)

如果不在故事板中添加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;
}

答案 2 :(得分:2)

完成Swift Playground示例

我能想到的最简单的例子是向UIImageView添加UIScrollView。这是100%的代码,您只需要向Playground添加PNG即可。我打电话给我Image.png。在游乐场中,您将看到在“实时视图”中呈现的整个内容。使用按住Ctrl键单击将一根手指放在屏幕上然后拖动时,可以进行双指缩放。直到内容放大大于屏幕平移将无法工作。双击图像可在1x和3x刻度之间切换。

基于Apple的Technical Note TN2154: UIScrollView and 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()