How to resize UIImageView based on UIImage's size/ratio in Swift 3?

前端 未结 8 1512
没有蜡笔的小新
没有蜡笔的小新 2020-11-28 19:01

I have a UIImageView and the user is able to download UIImages in various formats. The issue is that I need the UIImageView to resize

相关标签:
8条回答
  • 2020-11-28 19:17

    I modified @user8969729 's solution to replace the "fixed" width/height with "max", thus more like @JoshuaHart's solution. Handle the maxWidth == 0 / maxHeight == 0 case as you wish, since I always had both set I just quickly ignored that case.

    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)
       }
    }
    
    0 讨论(0)
  • 2020-11-28 19:20

    I spent many hours on this, and I finally got a solution that worked for me (Swift 3):

    • in IB, I set UIImageView's 'Content Mode' to 'Aspect Fit'
    • in IB, I set UIImageView's width constraint to be equal to whatever you want (in my case, the view's width)
    • in IB, I set UIImageView's height constraint to be equal to 0, and create a referencing outlet for it (say, constraintHeight)

    Then, when I need to display the image, I simply write the following (sampled from answers above):

    let ratio = image.size.width / image.size.height
    let newHeight = myImageView.frame.width / ratio
    constraintHeight.constant = newHeight
    view.layoutIfNeeded()
    

    Basically, this ensures that the image fills the UIImageView's width and forces the UIImageView's height to be equal to the image's height after it scaled

    0 讨论(0)
  • It looks like you want to resize an ImageView according to the image ratio and the container view's size, here is the example in Swift (Sorry,the former answer with a bug, I fixed it):

       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)
            }
        }
    
    0 讨论(0)
  • 2020-11-28 19:23

    Set your imageView to aspectFit, that will resize the image to not exceed your imageView's frame.

    You can get the size of your UIImage of your imageView with logic from this question - basically just get the height and width of the UIImage.

    Calculate the ratio and set the width/height of the imageView to fit you screen.

    There is also a similar question to your that you might get you answer from.

    0 讨论(0)
  • 2020-11-28 19:26

    The solution is also based on olearyj234's solution, but I think this will help more people.

    @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
        }
    
    }
    
    0 讨论(0)
  • 2020-11-28 19:30

    The solution I used is based on olearyj234's solution, but makes having no image take up essentially no space (or more specifically the minimum iOS will accept). It also uses ceil to avoid problems which can occur with non-integer values when UIImageView's are embedded in things like scrolling cells.

    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)
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题