32

我正在尝试使用 Auto Layout 实现UIScrollViewNew Way。我已经设置了从内部视图到滚动视图的约束,以便它可以自动计算自己的约束,contentSize这就像一个魅力——除了当我尝试放大或缩小时所有的地狱都崩溃了。我什至无法正确描述发生了什么,只能说内心的看法“搞砸了”。

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

有没有其他人遇到过这种行为?目前有什么方法可以放大UIScrollView以使用自动布局,而无需自己重新实现缩放行为?

4

3 回答 3

4

我见过的最好的答案是 Mark 的 ( https://stackoverflow.com/users/1051919/mark-kryzhanouski ),发布在这里:UIScrollView Zoom 不适用于 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]];
于 2013-04-23T00:55:24.023 回答
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;
}
于 2013-03-21T20:12:10.603 回答
2

完整的 Swift Playground 示例

我能想到的最简单的例子是将 a 添加UIImageViewUIScrollView. 这是 100% 的代码,您只需将 PNG 添加到 Playground。我打电话给我Image.png的。在 Playground 中,您会看到在“实时视图”中呈现的整个内容。捏缩放使用 Ctrl 键单击将一根手指放在屏幕上,然后四处拖动。直到内容放大到大于屏幕平移才会起作用。双击图像以在 1x 和 3x 比例之间切换。

基于 Apple 的技术说明 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()
于 2017-09-06T07:27:38.010 回答