【问题标题】:UIScrollView zooming with Auto LayoutUIScrollView 使用自动布局缩放
【发布时间】:2012-12-11 04:45:24
【问题描述】:

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

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

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

【问题讨论】:

  • 我知道你的意思。我有同样的问题。你想清楚了吗?它似乎与约束有关,我尝试删除 scrollViewWillBeginZooming:withView: 中的约束并将它们重新放在 scrollViewDidEndZooming:withView:atScale: 中,并且在缩放期间效果更好,但在缩放后内容错误地点。
  • @david:不,我从来没有解决过这个问题。我的结论是 UIKit 的各个部分根本不兼容 Auto Layout,因此在这些情况下我已经停止使用 Auto Layout(尤其是 UIScrollViewUIPageViewController)。
  • 我也有这个问题。我有一个带有嵌入式 imageView 的滚动视图,我试图只允许简单地缩放图像,这一切都很时髦并且扭曲了整个图像视图,同时在捏视图的同时跳跃大小。希望有人能解决这个问题。

标签: ios uiscrollview zooming autolayout


【解决方案1】:

我看到的最佳答案是 Mark 的 (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]];

【讨论】:

  • 当您说you have to anchor the image view that is nested in the scroll view, to the parent of the scroll view 时,是否需要执行任何操作才能产生这种行为?因为我已经以编程方式将约束设置为马克,你说,但我仍然无法使其工作。
【解决方案2】:

没有在情节提要中添加 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”)。
  • 追求“纯度”有什么意义。我提供了一个解决方案。
  • @AMayes 因为他可能需要使用 Autolayout 并且需要一个与之兼容的解决方案?
【解决方案3】:

完整的 Swift Playground 示例

我能想到的最简单的例子是将UIImageView 添加到UIScrollView。这是 100% 的代码,您只需将 PNG 添加到 Playground。我打电话给我的Image.png。在 Playground 中,您会看到在“实时视图”中呈现的整个内容。捏缩放使用 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()

【讨论】:

    猜你喜欢
    • 2014-11-27
    • 2013-11-07
    • 2013-01-06
    • 2013-01-04
    • 1970-01-01
    • 2016-05-16
    • 2015-05-09
    • 2011-09-27
    • 2016-10-25
    相关资源
    最近更新 更多