带有嵌入式 UIImageView 的 UIScrollView;如何让图像填满屏幕 [英] UIScrollView with Embedded UIImageView; how to get the image to fill the screen

查看:32
本文介绍了带有嵌入式 UIImageView 的 UIScrollView;如何让图像填满屏幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UIKit/程序化用户界面

UIKit/Programmatic UI

我有一个 UIScrollView,里面有一个 UIImageView.图像由用户选择设置,可以有各种尺寸.我想要的是图像最初填满屏幕(视图),然后可以一直缩放和滚动到图像的边缘.

I have an UIScrollView with an UIImageView inside. The image is set by user selection and can have all kinds of sizes. What I want is that the image initially fills the screen (view) and then can be zoomed and scrolled all the way to the edges of the image.

如果我将 ImageView 直接添加到视图(没有 scrollView),我会使用以下代码填充屏幕:

If I add the ImageView directly to the view (no scrollView), I get it to fill the screen with the following code:

        mapImageView.image = ProjectImages.projectDefaultImage
        mapImageView.translatesAutoresizingMaskIntoConstraints = false
        mapImageView.contentMode = .scaleAspectFill
        view.addSubview(mapImageView)

现在与滚动视图和嵌入的图像视图相同:

Now the same with the scrollView and the embedded imageView:

        view.insertSubview(mapImageScrollView, at: 0)
        mapImageScrollView.delegate = self
        mapImageScrollView.translatesAutoresizingMaskIntoConstraints = false
        mapImageScrollView.contentMode = .scaleAspectFill
        mapImageScrollView.maximumZoomScale = 4.0
        mapImageScrollView.pinToEdges(of: view, safeArea: true)
        
        mapImageView.image = ProjectImages.projectDefaultImage
        mapImageView.translatesAutoresizingMaskIntoConstraints = false
        mapImageView.contentMode = .scaleAspectFill
        mapImageScrollView.addSubview(mapImageView)

现在,如果图像的高度小于视图的高度,则图像不会填满屏幕,并且图像下方会留下一个空白的视图区域.我可以缩放和滚动,然后图像会填充视图.

And now, if the image's height is smaller than the view's height, the image does not fill the screen and I'm left with a blank view area below the image. I can zoom and scroll ok, and then the image does fill the view.

添加约束将根据需要填充视图,但会干扰缩放和滚动并阻止我在放大时到达图像的边缘.

Adding contsraints will fill the view as I want, but interferes with the zooming and scrolling and prevents me getting to the edges of the image when zoomed in.

如何正确设置?

推荐答案

您可能会发现这很有用...

You might find this useful...

它允许您在滚动视图中缩放图像,从居中开始并保持纵横比.

It allows you to zoom an image in a scrollView, starting with it centered and maintaining aspect ratio.

这是一个完整的实现.它的顶部有两个重要的变量:

Here's a complete implementation. It has two important variables at the top:

// can be .scaleAspectFill or .scaleAspectFit
var fitMode: UIView.ContentMode = .scaleAspectFill

// if fitMode is .scaleAspectFit, allowFullImage is ignored
// if fitMode is .scaleAspectFill, image will start zoomed to .scaleAspectFill
//  if allowFullImage is false, image will zoom back to .scaleAspectFill if "pinched in"
//  if allowFullImage is true, image can be "pinched in" to see the full image
var allowFullImage: Bool = true

一切都通过代码完成 - 没有 @IBOutlet 或其他连接 - 所以只需创建添加一个新的视图控制器并将其自定义类分配给 ZoomAspectViewController(并编辑名称您要使用的图像):

Everything is done via code - no @IBOutlet or other connections - so just create add a new view controller and assign its custom class to ZoomAspectViewController (and edit the name of the image you want to use):

class ZoomAspectViewController: UIViewController, UIScrollViewDelegate {
    
    var scrollView: UIScrollView!
    var imageView: UIImageView!
    var imageViewBottomConstraint: NSLayoutConstraint!
    var imageViewLeadingConstraint: NSLayoutConstraint!
    var imageViewTopConstraint: NSLayoutConstraint!
    var imageViewTrailingConstraint: NSLayoutConstraint!
    
    // can be .scaleAspectFill or .scaleAspectFit
    var fitMode: UIView.ContentMode = .scaleAspectFit
    
    // if fitMode is .scaleAspectFit, allowFullImage is ignored
    // if fitMode is .scaleAspectFill, image will start zoomed to .scaleAspectFill
    //  if allowFullImage is false, image will zoom back to .scaleAspectFill if "pinched in"
    //  if allowFullImage is true, image can be "pinched in" to see the full image
    var allowFullImage: Bool = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let img = UIImage(named: "myImage") else {
            fatalError("Could not load the image!!!")
        }
        
        scrollView = UIScrollView()
        imageView = UIImageView()
        
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        imageView.translatesAutoresizingMaskIntoConstraints = false
        
        imageView.contentMode = .scaleToFill
        
        scrollView.addSubview(imageView)
        view.addSubview(scrollView)
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: scrollView.topAnchor)
        imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
        imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor)
        imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor)

        NSLayoutConstraint.activate([
            
            scrollView.topAnchor.constraint(equalTo: g.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),

            imageViewTopConstraint,
            imageViewBottomConstraint,
            imageViewLeadingConstraint,
            imageViewTrailingConstraint,
            
        ])
        
        scrollView.delegate = self
        scrollView.minimumZoomScale = 0.1
        scrollView.maximumZoomScale = 5.0
        
        imageView.image = img
        imageView.frame.size = img.size
        
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: { _ in
            self.updateMinZoomScaleForSize(size, shouldSize: (self.scrollView.zoomScale == self.scrollView.minimumZoomScale))
            self.updateConstraintsForSize(size)
        }, completion: {
            _ in
        })
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updateMinZoomScaleForSize(scrollView.bounds.size)
        updateConstraintsForSize(scrollView.bounds.size)
        
        if fitMode == .scaleAspectFill {
            centerImageView()
        }
        
    }
    
    func updateMinZoomScaleForSize(_ size: CGSize, shouldSize: Bool = true) {
        guard let img = imageView.image else {
            return
        }
        
        var bShouldSize = shouldSize
        
        let widthScale = size.width / img.size.width
        let heightScale = size.height / img.size.height
        
        var minScale = min(widthScale, heightScale)
        let startScale = max(widthScale, heightScale)
        
        if fitMode == .scaleAspectFill && !allowFullImage {
            minScale = startScale
        }
        if scrollView.zoomScale < minScale {
            bShouldSize = true
        }
        scrollView.minimumZoomScale = minScale
        if bShouldSize {
            scrollView.zoomScale = fitMode == .scaleAspectFill ? startScale : minScale
        }
    }
    
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        updateConstraintsForSize(scrollView.bounds.size)
    }
    
    func centerImageView() -> Void {
        let yOffset = (scrollView.frame.size.height - imageView.frame.size.height) / 2
        let xOffset = (scrollView.frame.size.width - imageView.frame.size.width) / 2
        scrollView.contentOffset = CGPoint(x: -xOffset, y: -yOffset)
    }
    
    func updateConstraintsForSize(_ size: CGSize) {
        let yOffset = max(0, (size.height - imageView.frame.height) / 2)
        imageViewTopConstraint.constant = yOffset
        imageViewBottomConstraint.constant = yOffset
        
        let xOffset = max(0, (size.width - imageView.frame.width) / 2)
        imageViewLeadingConstraint.constant = xOffset
        imageViewTrailingConstraint.constant = xOffset
        
        view.layoutIfNeeded()
    }
    
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
}


编辑

例如,我使用了这张图片 (2560 x 1440):

As an example, I used this image (2560 x 1440):

我在发布时得到了这个结果:

and I get this result on launch:

和最大放大 (5.0) 滚动到顶部中心:

and maximum zoom in (5.0) scrolled to top-center:

编辑 2

发布时相同的图像:

var fitMode: UIView.ContentMode = .scaleAspectFill

而不是.scaleAspectFit:

这篇关于带有嵌入式 UIImageView 的 UIScrollView;如何让图像填满屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆