Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize UIImageView after loading image from URL w/ Kingfisher

I would like to resize any downloaded images so they maintain their aspect ratio, however are all as wide as the UITableViewCell they are rendered in.

My UIImageView is configured with the contentMode as AspectFit and I have the following anchors on my cell:

enter image description here

I am almost there with the current attempt:

class AnimatedImageTableViewCell: UITableViewCell {
    @IBOutlet weak var gifView: AnimatedImageView!
    @IBOutlet weak var imageHeightAnchor: NSLayoutConstraint!

    var refreshCell: (() -> Void)?

    func render(imageUrl: String) {
        guard let url = URL(string: imageUrl) else { return }

        gifView.kf.setImage(with: url) { result in
            switch result {
            case .success(let value):
                let ratio = value.image.size.width / value.image.size.height
                let newHeight = self.gifView.frame.width / ratio
                self.imageHeightAnchor.constant = newHeight
                self.refreshCell?()
            case .failure(let error):
                print(error) // The error happens
            }
        }
    }
}

Also:

class HomeViewController: UITableViewController {

    let images = [
        "https://cdn-images-1.medium.com/max/1600/1*OJxJTJLSyqJ0nMeuswuCSQ.gif",
        "https://static1.squarespace.com/static/552a5cc4e4b059a56a050501/565f6b57e4b0d9b44ab87107/566024f5e4b0354e5b79dd24/1449141991793/NYCGifathon12.gif",
        "https://media2.giphy.com/avatars/100soft/WahNEDdlGjRZ.gif"
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.tableFooterView = UIView()
        tableView.estimatedRowHeight = 200
        tableView.rowHeight = UITableView.automaticDimension
        tableView.allowsSelection = false

        let nib = UINib(nibName: "AnimatedImageTableViewCell", bundle: nil)
        tableView.register(nib, forCellReuseIdentifier: "cellId")

    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return images.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let imagePath = images[indexPath.item]

        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! AnimatedImageTableViewCell

        cell.refreshCell = {
            tableView.reloadRows(at: [indexPath], with: .automatic)
        }

        cell.render(imageUrl: imagePath)

        return cell
    }
}

However in some case the cell is too tall. The images renders full width, with the correct aspect ratio, there is just way too much space above and below the image.

I also get errors in the console as follows:

(
    "<NSLayoutConstraint:0x600000329770 Kingfisher.AnimatedImageView:0x7fd339e19330.height == 268.5   (active)>",
    "<NSLayoutConstraint:0x60000032a8f0 Kingfisher.AnimatedImageView:0x7fd339e19330.top == UITableViewCellContentView:0x7fd339e1a280.topMargin + 8   (active)>",
    "<NSLayoutConstraint:0x60000032a850 UITableViewCellContentView:0x7fd339e1a280.bottomMargin == Kingfisher.AnimatedImageView:0x7fd339e19330.bottom + 8   (active)>",
    "<NSLayoutConstraint:0x60000032a7b0 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600001908ee0'UIViewLayoutMarginsGuide']-(8)-|   (active, names: '|':UITableViewCellContentView:0x7fd339e1a280 )>",
    "<NSLayoutConstraint:0x600000323980 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fd339e1a280.height == 450.5   (active)>",
    "<NSLayoutConstraint:0x60000032a6c0 'UIView-topMargin-guide-constraint' V:|-(8)-[UILayoutGuide:0x600001908ee0'UIViewLayoutMarginsGuide']   (active, names: '|':UITableViewCellContentView:0x7fd339e1a280 )>"
)

enter image description here

like image 542
Tim J Avatar asked Jan 21 '19 15:01

Tim J


People also ask

How do I increase the size of an image in a URL?

You can resize images by passing a size parameter in the query string portion of the URL. The size parameter replaces the larger of the height or width parameters.

How do I change aspect ratio in UIImageView?

If you are resizing UIImageView manually, set the content mode to UIViewContentModeScaleAspectFill . If you want to keep content mode UIViewContentModeScaleAspectFit do not resize imageview to 313. Image will adjust maximum possible width and height , keeping it's aspect ratio.


1 Answers

You could simply try to resize the image view after setting its image property. For example:

class ResizableImageView: UIImageView {

  override var image: UIImage? {
    didSet {
      guard let image = image else { return }

      let resizeConstraints = [
        self.heightAnchor.constraint(equalToConstant: image.size.height),
        self.widthAnchor.constraint(equalToConstant: image.size.width)
      ]

      if superview != nil {
        addConstraints(resizeConstraints)
      }
    }
  }
}

Then, add its normal constraints omitting heightAnchor and widthAnchor ones, because those will be added as soon as the image gets added (I'd recommend not using interface builder at this point):

let imageView = ResizableImageView(frame: .zero)
imageView.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(imageView)

// These are only illustrative constraints
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

imageView.image = image

Here's a complete and fully functional example:

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    downloadImage(
      fromURL: URL(string: "https://img.evbuc.com/https%3A%2F%2Fcdn.evbuc.com%2Fimages%2F33105753%2F184176199496%2F1%2Foriginal.jpg?h=200&w=450&rect=0%2C0%2C400%2C200&s=a92a5a03c153d312d682b2dfedd6a6ad")!,
      completionHandler: { [weak self] image in
        guard let self = self, let image = image else { return }

        let imageView = ResizableImageView(frame: .zero)
        imageView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(imageView)

        imageView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        imageView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

        imageView.image = image
      })
  }

  func downloadImage(fromURL url: URL, completionHandler: @escaping (UIImage?) -> Void) {
    let operationQueue = OperationQueue()

    operationQueue.addOperation {
      guard let data = try? Data(contentsOf: url) else {
        OperationQueue.main.addOperation {
          completionHandler(nil)
        }

        return
      }

      OperationQueue.main.addOperation {
        let image = UIImage(data: data)
        completionHandler(image)
      }
    }
  }
}
like image 95
Murilo Paixão Avatar answered Sep 25 '22 07:09

Murilo Paixão