swift-无法使用 AutoLayout 在 UIScrollView 中居中 UIImageView
Posted
技术标签:
【中文标题】swift-无法使用 AutoLayout 在 UIScrollView 中居中 UIImageView【英文标题】:swift-Can't center UIImageView in UIScrollView with AutoLayout 【发布时间】:2015-02-16 02:41:12 【问题描述】:我搜索了很多关于UIScrollView
的文章,其中包含UIImageView
,但都没有AutoLayout
信息。我所做的是:在UIViewController
中放置一个UIScrollView
,约束为前10,前10,后50,尾10;在UIScrollView
内放置一个UIImageView
,约束为前0,前0,下0,尾0。我想要的很简单:让我的UIImageView
适合我的UIScrollView
,当应用程序第一次加载时,让我的@ 987654330@ 水平和垂直居中。现在我可以看到图像并且正好适合屏幕但是图像正好在UIScrollView
的顶部。(注意:在这种情况下,我的图像在缩放到最小zoomScale
后的宽度等于宽度UIScrollView
,我的图片缩放到最小后的高度zoomScale
小于UIScrollView
的宽度。)
我真的无法将我的UIImageView
垂直移动到UIScrollView
的中心,也找不到出错的地方。非常感谢。
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view.
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
func centerScrollViewContents()
let boundsSize = scrollView.bounds.size
var contentsFrame = imageView.frame
if contentsFrame.size.width < boundsSize.width
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0
else
contentsFrame.origin.x = 0.0
if contentsFrame.size.height < boundsSize.height
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0
else
contentsFrame.origin.y = 0.0
override func viewDidLayoutSubviews()
let myImage = UIImage(named: "7.jpg")
imageView.image = myImage
let weightScale = scrollView.bounds.size.width / myImage!.size.width
let heightScale = scrollView.bounds.size.height / myImage!.size.height
let minScale = min(weightScale, heightScale)
let imagew = myImage!.size.width * minScale
let imageH = myImage!.size.height * minScale
let imageRect = CGRectMake(0, 0, imagew, imageH)
imageView.frame = imageRect
scrollView.contentSize = myImage!.size
scrollView.maximumZoomScale = 1.0
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
imageView.frame = imageRect
centerScrollViewContents()
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
return imageView
【问题讨论】:
我认为是因为自动布局问题。我需要做什么? 【参考方案1】:支持 pic-o-matic 的回答。我有一个案例,只有当它小于滚动视图框架时,我才需要将图像居中。使用插图制作一个简单的解决方案。
if imageView.frame.height <= scrollView.frame.height
let shiftHeight = scrollView.frame.height/2.0 - scrollView.contentSize.height/2.0
scrollView.contentInset.top = shiftHeight
if imageView.frame.width <= scrollView.frame.width
let shiftWidth = scrollView.frame.width/2.0 - scrollView.contentSize.width/2.0
scrollView.contentInset.left = shiftWidth
【讨论】:
我把它放在public func scrollViewDidZoom(scrollView: UIScrollView)
上,效果很好。我还在这两种情况下都添加了else scrollView.contentInset.top = 0
谢谢!【参考方案2】:
我遇到了同样的问题。我找到了一个完美的解决方案,看看这个 github 项目:https://github.com/evgenyneu/ios-imagescroll-swift
它的基本工作原理如下:如果图像缩小得足够远,它会调整您的约束以使图像居中,并使其能够在宽度或高度超过容器的相应宽度或高度后进行缩放和滚动。
感谢这个帖子:Zooming UIImageView inside UIScrollView with autolayout(提供 obj-c 和 swift 解决方案)!
// ViewController.swift
// image-scroll-swift
//
// Created by Evgenii Neumerzhitckii on 4/10/2014.
// Copyright (c) 2014 Evgenii Neumerzhitckii. All rights reserved.
//
import UIKit
let imageScrollLargeImageName = "wallabi.jpg"
class ViewController: UIViewController, UIScrollViewDelegate
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var imageConstraintTop: NSLayoutConstraint!
@IBOutlet weak var imageConstraintRight: NSLayoutConstraint!
@IBOutlet weak var imageConstraintLeft: NSLayoutConstraint!
@IBOutlet weak var imageConstraintBottom: NSLayoutConstraint!
var lastZoomScale: CGFloat = -1
override func viewDidAppear(animated: Bool)
super.viewDidAppear(animated)
imageView.image = UIImage(named: imageScrollLargeImageName)
scrollView.delegate = self
updateZoom()
// Update zoom scale and constraints
// It will also animate because willAnimateRotationToInterfaceOrientation
// is called from within an animation block
//
// DEPRECATION NOTICE: This method is said to be deprecated in iOS 8.0. But it still works.
override func willAnimateRotationToInterfaceOrientation(
toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval)
super.willAnimateRotationToInterfaceOrientation(toInterfaceOrientation, duration: duration)
updateZoom()
func updateConstraints()
if let image = imageView.image
let imageWidth = image.size.width
let imageHeight = image.size.height
let viewWidth = view.bounds.size.width
let viewHeight = view.bounds.size.height
// center image if it is smaller than screen
var hPadding = (viewWidth - scrollView.zoomScale * imageWidth) / 2
if hPadding < 0 hPadding = 0
var vPadding = (viewHeight - scrollView.zoomScale * imageHeight) / 2
if vPadding < 0 vPadding = 0
imageConstraintLeft.constant = hPadding
imageConstraintRight.constant = hPadding
imageConstraintTop.constant = vPadding
imageConstraintBottom.constant = vPadding
// Makes zoom out animation smooth and starting from the right point not from (0, 0)
view.layoutIfNeeded()
// Zoom to show as much image as possible unless image is smaller than screen
private func updateZoom()
if let image = imageView.image
var minZoom = min(view.bounds.size.width / image.size.width,
view.bounds.size.height / image.size.height)
if minZoom > 1 minZoom = 1
scrollView.minimumZoomScale = minZoom
// Force scrollViewDidZoom fire if zoom did not change
if minZoom == lastZoomScale minZoom += 0.000001
scrollView.zoomScale = minZoom
lastZoomScale = minZoom
// UIScrollViewDelegate
// -----------------------
func scrollViewDidZoom(scrollView: UIScrollView)
updateConstraints()
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
return imageView
确保您的故事板包含视图控制器。在“视图”中放置一个“滚动视图”,在该“滚动视图”中放置一个“图像视图”。
在“滚动视图”和“视图”之间建立 0(或您喜欢的任何值)的顶部/底部/前导/尾随约束。然后在图像和滚动视图之间建立相同的约束并将它们连接到@IBOutlets。
这应该可以正常工作,因为代码会在您缩放时更改约束。
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。 感谢 beresfordt,我的第一篇文章;)我添加了代码,希望对您有所帮助。【参考方案3】:我也有同样的“问题”……不过没有自动布局。我想出了这个解决方案(使用插图使图像居中)。 automaticAdjustsScrollViewInsets 属性必须设置为 false。
override func viewDidLoad()
super.viewDidLoad()
//create scrollview
self.automaticallyAdjustsScrollViewInsets = false
myScrollview = MyScrollview(frame: self.view.frame)
myScrollview.alwaysBounceHorizontal = true
myScrollview.alwaysBounceVertical = true
myScrollview.delegate = self
//....
override func viewWillLayoutSubviews()
//setup frame portrait and landscape
myScrollview.frame = self.view.frame
myScrollview.zoomScale = self.view.frame.width / photo.size.width
myScrollview.minimumZoomScale = self.view.bounds.width / photo.size.width
// calculate inset to center vertically
let shift = myScrollview.frame.height/2.0 - myScrollview.contentSize.height/2.0
myScrollview.contentInset.top = shift
override func viewDidLayoutSubviews()
func scrollViewDidZoom(scrollView: UIScrollView)
let shift = myScrollview.frame.height/2.0 - myScrollview.contentSize.height/2.0
myScrollview.contentInset.top = shift
我使用 UIScrollView 的一个子类“MyScrollview”来“查看”发生了什么,我认为这对于了解滚动视图、边界框和内容大小很有用:
//
// MyScrollview.swift
// CampingDeHooiberg
//
// Created by Andre Lam on 09-03-15.
// Copyright (c) 2015 Andre Lam. All rights reserved.
//
import UIKit
class MyScrollview: UIScrollView
override var bounds: CGRect willSet println("bounds set: \(newValue) contentSize:\(self.contentSize) frame:\(self.frame)")
override var contentSize: CGSize willSet println("bounds:\(self.bounds) set contentsize:\(newValue) frame: \(self.frame)")
override var frame: CGRect willSet println("bounds: \(self.bounds) contentSize:\(self.contentSize) frame set:\(newValue)")
override init(frame: CGRect)
super.init(frame: frame)
required init(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
【讨论】:
以上是关于swift-无法使用 AutoLayout 在 UIScrollView 中居中 UIImageView的主要内容,如果未能解决你的问题,请参考以下文章
使用 Swift (AutoLayout) 固定 UIImage 的宽度和高度
AutoLayout - 使用水平约束保持图像的比例(Swift Xcode 6)
使用 AutoLayout 以编程方式将 UILabel 添加到 ScrollView (swift)
使用 Swift、autolayout 和 SnapKit 使带有 UIImageView 的 UIScrollView 自动缩放内容