![](/img/trans.png)
[英]How to resize a UIImageView based on UIImage size and fit the screen's width
[英]How to resize UIImageView based on UIImage's size/ratio in Swift 3?
我花了很多时间试图找到解决您遇到的相同问题的方法,这是唯一对我有用的解决方案(Swift 4,Xcode 9.2):
class ScaledHeightImageView: UIImageView {
override var intrinsicContentSize: CGSize {
if let myImage = self.image {
let myImageWidth = myImage.size.width
let myImageHeight = myImage.size.height
let myViewWidth = self.frame.size.width
let ratio = myViewWidth/myImageWidth
let scaledHeight = myImageHeight * ratio
return CGSize(width: myViewWidth, height: scaledHeight)
}
return CGSize(width: -1.0, height: -1.0)
}
}
将该类添加到项目中,并将 UIImageView 设置为自定义类 ScaledHeightImageView。 图像视图的内容模式是 Aspect Fit。
我的问题和这篇文章中提到的一样。 在我的原型 TableViewCell 的 ContentView 中,我有一个垂直 StackView 约束到每个边缘。 在 StackView 里面有一个 Label、ImageView 和另一个 Label。 将 ImageView 设置为 AspectFit 是不够的。 图像将是正确的大小和比例,但 ImageView 没有包裹实际图像,在图像和标签之间留下了一堆额外的空间(就像上图一样)。 ImageView 高度似乎与原始图像的高度相匹配,而不是调整后图像的高度(在 aspectFit 完成它的工作之后)。 由于各种原因,我发现的其他解决方案并没有完全解决问题。 我希望这可以帮助别人。
我花了很多时间在这上面,我终于得到了一个对我有用的解决方案( Swift 3 ):
constraintHeight
)然后,当我需要显示图像时,我只需编写以下内容(从上面的答案中取样):
let ratio = image.size.width / image.size.height
let newHeight = myImageView.frame.width / ratio
constraintHeight.constant = newHeight
view.layoutIfNeeded()
基本上,这可以确保图像填充 UIImageView 的宽度并强制 UIImageView 的高度在缩放后等于图像的高度
看起来您想根据图像比例和容器视图的大小调整 ImageView 的大小,这是 Swift 中的示例(对不起,前一个答案有错误,我已修复):
let containerView = UIView(frame: CGRect(x:0,y:0,width:320,height:500))
let imageView = UIImageView()
if let image = UIImage(named: "a_image") {
let ratio = image.size.width / image.size.height
if containerView.frame.width > containerView.frame.height {
let newHeight = containerView.frame.width / ratio
imageView.frame.size = CGSize(width: containerView.frame.width, height: newHeight)
}
else{
let newWidth = containerView.frame.height * ratio
imageView.frame.size = CGSize(width: newWidth, height: containerView.frame.height)
}
}
我使用的解决方案是基于olearyj234 的解决方案,但使没有图像占用基本上没有空间(或者更具体地说,最小的 iOS 将接受)。 它还使用 ceil 来避免当 UIImageView 嵌入在滚动单元格等内容中时非整数值可能出现的问题。
class FixedWidthAspectFitImageView: UIImageView
{
override var intrinsicContentSize: CGSize
{
// VALIDATE ELSE RETURN
// frameSizeWidth
let frameSizeWidth = self.frame.size.width
// image
// ⓘ In testing on iOS 12.1.4 heights of 1.0 and 0.5 were respected, but 0.1 and 0.0 led intrinsicContentSize to be ignored.
guard let image = self.image else
{
return CGSize(width: frameSizeWidth, height: 1.0)
}
// MAIN
let returnHeight = ceil(image.size.height * (frameSizeWidth / image.size.width))
return CGSize(width: frameSizeWidth, height: returnHeight)
}
}
在 ViewController 中放置一个 ImageView 并在viewDidLoad()
创建一个名为imageView
的插座。
override func viewDidLoad() { super.viewDidLoad() var image = UIImage(contentsOfFile: "yourFilePath")! var aspectR: CGFloat = 0.0 aspectR = image.size.width/image.size.height imageView.translatesAutoresizingMaskIntoConstraints = false imageView.image = image imageView.contentMode = .scaleAspectFit NSLayoutConstraint.activate([ imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor), imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor), imageView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor), imageView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor), imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1/aspectR) ]) }
NSLayoutConstraint.activate
数组的最后 3 行确保图像宽度保持在容器视图的边界内,并且高度保持与宽度成比例(即保持纵横比并将imageView
高度缩小到所需的最小值)。
Interface Builder 中的视图控制器: Main.storyboard
正在运行的应用程序中 UIImageView 的快照: appSnapshot
该解决方案也是基于olearyj234的解决方案,但我认为这会帮助更多人。
@IBDesignable
class DynamicImageView: UIImageView {
@IBInspectable var fixedWidth: CGFloat = 0 {
didSet {
invalidateIntrinsicContentSize()
}
}
@IBInspectable var fixedHeight: CGFloat = 0 {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
var size = CGSize.zero
if fixedWidth > 0 && fixedHeight > 0 { // 宽高固定
size.width = fixedWidth
size.height = fixedHeight
} else if fixedWidth <= 0 && fixedHeight > 0 { // 固定高度动态宽度
size.height = fixedHeight
if let image = self.image {
let ratio = fixedHeight / image.size.height
size.width = image.size.width * ratio
}
} else if fixedWidth > 0 && fixedHeight <= 0 { // 固定宽度动态高度
size.width = fixedWidth
if let image = self.image {
let ratio = fixedWidth / image.size.width
size.height = image.size.height * ratio
}
} else { // 动态宽高
size = image?.size ?? .zero
}
return size
}
}
将您的 imageView 设置为 aspectFit,这将调整图像大小以不超过您的 imageView 的框架。
您可以使用this question的逻辑获取imageView的UIImage的大小-基本上只需获取UIImage的高度和宽度。
计算比例并设置 imageView 的宽度/高度以适合您的屏幕。
我修改了@user8969729 的解决方案,用“max”替换了“固定”宽度/高度,因此更像是@JoshuaHart 的解决方案。 按照您的意愿处理maxWidth == 0
/ maxHeight == 0
情况,因为我总是设置了这两种情况,所以我很快就忽略了这种情况。
public class AdjustsViewBoundsImageView: UIImageView {
/// The maximum width that you want this imageView to grow to.
@objc dynamic var maxWidth: CGFloat = 0 {
didSet {
invalidateIntrinsicContentSize()
}
}
/// The maximum height that you want this imageView to grow to.
@objc dynamic var maxHeight: CGFloat = 0 {
didSet {
invalidateIntrinsicContentSize()
}
}
private var maxAspectRatio: CGFloat { return maxWidth / maxHeight }
override public var intrinsicContentSize: CGSize {
guard let classImage = self.image else { return super.intrinsicContentSize }
if maxHeight == 0 || maxWidth == 0 {
return super.intrinsicContentSize
}
let imageWidth = classImage.size.width
let imageHeight = classImage.size.height
let aspectRatio = imageWidth / imageHeight
// Width is greater than height, return max width image and new height.
if imageWidth > imageHeight {
let newHeight = maxWidth/aspectRatio
return CGSize(width: maxWidth, height: newHeight)
}
// Height is greater than width, return max height and new width.
if imageHeight > imageWidth {
// If the aspect ratio is larger than our max ratio, then using max width
// will be hit before max height.
if aspectRatio > maxAspectRatio {
let newHeight = maxWidth/aspectRatio
return CGSize(width: maxWidth, height: newHeight)
}
let newWidth = maxHeight * aspectRatio
return CGSize(width: newWidth, height: maxHeight)
}
// Square image, return the lesser of max width and height.
let squareMinimumValue = min(maxWidth, maxHeight)
return CGSize(width: squareMinimumValue, height: squareMinimumValue)
}
}
这里的很多答案在计算intrinsicContentSize
时都使用frame
。 文档不鼓励这样做:
这种固有大小必须独立于内容框架,因为例如,无法根据更改的高度将更改的宽度动态传达给布局系统。
我发现希望根据以下条件动态设置UIImageView
高度:
image
的纵横比作为一个常见问题,我在下面提供了一个可能的解决方案。
我认为最好通过向UIImageView
添加一个NSLayoutConstraint
来解决这个问题,该UIImageView
约束了widthAnchor
和heightAnchor
(反之亦然),以便multiplier
与图像的纵横比相匹配。 我创建了一个UIImageView
子类,它正是这样做的:
import UIKit
/// `AdjustableImageView` is a `UIImageView` which should have a fixed width or height.
/// It will add an `NSLayoutConstraint` such that it's width/height (aspect) ratio matches the
/// `image` width/height ratio.
class AdjustableImageView: UIImageView {
/// `NSLayoutConstraint` constraining `heightAnchor` relative to the `widthAnchor`
/// with the same `multiplier` as the inverse of the `image` aspect ratio, where aspect
/// ratio is defined width/height.
private var aspectRatioConstraint: NSLayoutConstraint?
/// Override `image` setting constraint if necessary on set
override var image: UIImage? {
didSet {
updateAspectRatioConstraint()
}
}
// MARK: - Init
override init(image: UIImage?) {
super.init(image: image)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
// MARK: - Setup
/// Shared initializer code
private func setup() {
// Set default `contentMode`
contentMode = .scaleAspectFill
// Update constraints
updateAspectRatioConstraint()
}
// MARK: - Resize
/// De-active `aspectRatioConstraint` and re-active if conditions are met
private func updateAspectRatioConstraint() {
// De-active old constraint
aspectRatioConstraint?.isActive = false
// Check that we have an image
guard let image = image else { return }
// `image` dimensions
let imageWidth = image.size.width
let imageHeight = image.size.height
// `image` aspectRatio
guard imageWidth > 0 else { return }
let aspectRatio = imageHeight / imageWidth
guard aspectRatio > 0 else { return }
// Create a new constraint
aspectRatioConstraint = heightAnchor.constraint(
equalTo: widthAnchor,
multiplier: aspectRatio
)
// Activate new constraint
aspectRatioConstraint?.isActive = true
}
}
如果内容模式设置为aspectFit或aspectFill ,答案会有所不同:
extension UIImageView {
var intrinsicScaledContentSize: CGSize? {
switch contentMode {
case .scaleAspectFit:
// aspect fit
if let image = self.image {
let imageWidth = image.size.width
let imageHeight = image.size.height
let viewWidth = self.frame.size.width
let ratio = viewWidth/imageWidth
let scaledHeight = imageHeight * ratio
return CGSize(width: viewWidth, height: scaledHeight)
}
case .scaleAspectFill:
// aspect fill
if let image = self.image {
let imageWidth = image.size.width
let imageHeight = image.size.height
let viewHeight = self.frame.size.width
let ratio = viewHeight/imageHeight
let scaledWidth = imageWidth * ratio
return CGSize(width: scaledWidth, height: imageHeight)
}
default: return self.bounds.size
}
return nil
}
}
如果需要,这可以很容易地转换为使用 IBOutlets。 我的用例涉及以编程方式添加 imageViews。 这是非常可靠的。 只需在您的项目中创建一个新文件并添加以下代码。
import UIKit
/// Resizeable Image View that takes a max height and max width
/// Will resize the imageView to best fit for the aspect ratio of the image,
/// With the given space provided.
public class ResizeableImageView: UIImageView {
private var widthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
// MARK: - INITIALIZERS:
public override init(image: UIImage?) {
super.init(image: image)
}
/// Given the max width and height, resizes the imageView to fit the image.
/// - IMPORTANT: This subclass adds a height and width constraint.
/// - Parameters:
/// - image: (UIImage?) The image to add to the imageView.
/// - maxWidth: (CGFloat) The max width you would like the imageView to grow to.
/// - maxHeight: (CGFloat) The max height you would like the imageView to grow to.
convenience init(image: UIImage?, maxWidth: CGFloat, maxHeight: CGFloat) {
self.init(image: image)
widthConstraint = constrain(width: maxWidth)
heightConstraint = constrain(height: maxHeight)
}
@available (*, unavailable) required internal init?(coder aDecoder: NSCoder) { nil }
// MARK: - VARIABLES:
/// The maximum width that you want this imageView to grow to.
private var maxWidth: CGFloat {
get { widthConstraint?.constant ?? 0 }
set { widthConstraint?.constant = newValue }
}
/// The maximum height that you want this imageView to grow to.
private var maxHeight: CGFloat {
get { heightConstraint?.constant ?? 0 }
set { heightConstraint?.constant = newValue }
}
private var maxAspectRatio: CGFloat { maxWidth / maxHeight }
override public var intrinsicContentSize: CGSize {
guard let classImage = self.image else { return frame.size }
let imageWidth = classImage.size.width
let imageHeight = classImage.size.height
let aspectRatio = imageWidth / imageHeight
// Width is greater than height, return max width image and new height.
if imageWidth > imageHeight {
let newHeight = maxWidth/aspectRatio
self.widthConstraint?.constant = maxWidth
self.heightConstraint?.constant = newHeight
return CGSize(width: maxWidth, height: newHeight)
}
// Height is greater than width, return max height and new width.
if imageHeight > imageWidth {
// If the aspect ratio is larger than our max ratio, then using max width
// will be hit before max height.
if aspectRatio > maxAspectRatio {
let newHeight = maxWidth/aspectRatio
self.widthConstraint?.constant = maxWidth
self.heightConstraint?.constant = newHeight
return CGSize(width: maxWidth, height: newHeight)
}
let newWidth = maxHeight * aspectRatio
self.widthConstraint?.constant = newWidth
self.heightConstraint?.constant = maxHeight
return CGSize(width: newWidth, height: maxHeight)
}
// Square image, return the lesser of max width and height.
let squareMinimumValue = min(maxWidth, maxHeight)
self.widthConstraint?.constant = squareMinimumValue
self.heightConstraint?.constant = squareMinimumValue
return CGSize(width: squareMinimumValue, height: squareMinimumValue)
}
}
let imageView = ResizeableImageView(image: image, maxWidth: 250, maxHeight: 250)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.