我花了很多时间寻找解决方案,针对你遇到的相同问题,这是唯一有效的解决方案(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)
}
}
containerView.frame.width < containerView.frame.height
而不是 containerView.frame.width > containerView.frame.height
是有效的。此外,如果图像具有相同的高度和宽度,则此方法无法正常工作。 - John Codeos在ViewController中放置一个ImageView并在viewDidLoad()
中创建一个名为imageView
的outlet。
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
的高度缩小到最小所需值)。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)
}
}
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
}
}
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
}
}
@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
}
}
iOS 根据 UIImage 大小创建 UIImageView
基于框架的[关于]
func addImageView(image: UIImage, x: CGFloat = 0, y: CGFloat = 0) {
let imageViewSize = self.getImageViewSize(image: image, minSize: minSize)
let imageView = UIImageView(
frame: CGRect(
x: x,
y: y,
width: imageViewSize.width,
height: imageViewSize.height
)
)
imageView.image = image
self.view.addSubview(imageView)
}
func getImageViewSize(image: UIImage, minSize: Double) -> CGSize {
let imageSize = image.size
let imageWidth = imageSize.width
let imageHeight = imageSize.height
let imageRatio = imageWidth/imageHeight
if imageWidth < imageHeight {
//portrait
return CGSize(width: minSize, height: minSize / imageRatio)
} else {
//landscape
return CGSize(width: minSize * imageRatio, height: minSize)
}
}
func getViewSize(size: CGSize, maxSize: CGSize) -> CGSize {
let width = size.width
let height = size.height
let maxWidth = maxSize.width
let maxHeight = maxSize.height
let resultWidth = maxHeight * width / height
if resultWidth <= maxWidth {
return CGSize(width: resultWidth, height: maxHeight)
} else {
// resultHeight <= maxHeight
let resultHeight = maxWidth * height / width
return CGSize(width: maxWidth, height: resultHeight)
}
}
func setImage(_ image: UIImage?) {
if let image = image {
if let superView = self.uiImageView.superview {
let size = getViewSize(size: image.size, maxSize: superView.frame.size)
self.uiImageWidthConstraint.constant = size.width
self.uiImageHeightConstraint.constant = size.height
}
}
}
将您的imageView设置为aspectFit,这将调整图像大小以不超过您的imageView框架。
您可以通过this question中的逻辑获取imageView的UIImage的大小 - 基本上只需获取UIImage的高度和宽度。
计算比率并设置imageView的宽度/高度以适应屏幕。
还有一个similar question与您的问题类似,您可能会从中获得答案。
UIImageView
的大小调整为包含的UIImage
的大小。他并不想根据UIImage
的大小来调整包含该UIImage
的UIImageView
的大小。换句话说,他希望让UIImage
确定UIImageView
的大小。他不想让UIImageView
决定UIImage
的大小。 - UtkuUIImageView
设置为相同的比例,这样就不会有多余的空间。 - Ben Ong