AechoLiu
AechoLiu

Reputation: 18428

How to get the displayed image frame from UIImageView?

I modify the UIImageView's contentMode property. So my image's frame is not equal to the frame of UIImageView. My problem is how to retrive the image's frame from UIImageView.

As the following example, the orange rectangle is the UIImageView's border. It is obviously that the frame of image is not the same as UIImageView.

Figure 1

Upvotes: 38

Views: 20687

Answers (6)

Jagveer Singh
Jagveer Singh

Reputation: 2328

Its very easy now

import AVKit
    
let rect = AVMakeRect(aspectRatio: image.size, insideRect: containerView.bounds);

Upvotes: 6

Avinash
Avinash

Reputation: 4372

Use this api from AVFoundation

#import <AVFoundation/AVFoundation.h>

CGRect imageRect = 
    AVMakeRectWithAspectRatioInsideRect(imageView.image.size, imageView.bounds);

Upvotes: 12

agibson007
agibson007

Reputation: 4393

The easiest way is to use AVMakeRectWithAspectRatioInsideRect. Just import AVFoundation and you can get the rect in a single line of Code. Swift 4. Be sure to import AVFoundation.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var imageView = UIImageView()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        imageView.frame = self.view.bounds
        imageView.contentMode = .scaleAspectFit
        imageView.backgroundColor = .blue
        imageView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        self.view.addSubview(imageView)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        URLSession.shared.dataTask(with: URL(string: "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?w=940&h=650&dpr=2&auto=compress&cs=tinysrgb")!) { (data, response, error) in
            guard let dt = data else{print("error");return}
            DispatchQueue.main.async {
                guard let image = UIImage(data: dt) else{print("error");return}
                self.imageView.image = image
                self.imageView.layoutIfNeeded()
                let realImageRect = AVMakeRect(aspectRatio: image.size, insideRect: self.imageView.bounds)


                //proof
                let view = UIView(frame: realImageRect)
                view.layer.borderColor = UIColor.green.cgColor
                view.layer.borderWidth = 3
                self.view.addSubview(view)
            }
        }.resume()
    }
}

Upvotes: 3

ericxu1983
ericxu1983

Reputation: 111

 if you want to calculate it yourself, use below code written by me.

func getImageFrameInImageView(imageView : UIImageView) -> CGRect {
    /*
    by 徐明刚, [email protected]
    算法:
        设高宽比 r = h/w, 则:r(imageView) 缩写成r(v), r(image)缩写为r(i), 
        if r(i) > r(v), 则
        h(i) = h(v), 
        h(i) / w(i) = r(i) -> w(i) = h(i) / r(i)
        y = 0
        x = (w(v) / 2)  - (w(i) / 2)
    反之
    */

    let image = imageView.image!
    let wi = image.size.width
    let hi = image.size.height
    print("wi:\(wi), hi:\(hi)")

    let wv = imageView.frame.width
    let hv = imageView.frame.height
    print("wv:\(wv), hv:\(hv)")

    let ri = hi / wi
    let rv = hv / wv
    print("ri:\(ri), rv:\(rv)")

    var x, y, w, h: CGFloat

    if ri > rv {
        h = hv
        w = h / ri
        x = (wv / 2) - (w / 2)
        y = 0
    } else {
        w = wv
        h = w * ri
        x = 0
        y = (hv / 2) - (h / 2)
    }

    return CGRect(x: x, y: y, width: w, height: h)
}

To test if the function is right or not, I've used another view identifying the border of the image in UIImageView.

    let frameIdentifyBorderView = UIView(frame: imageFrameInImageView)
    frameIdentifyBorderView.layer.borderWidth = 3
    frameIdentifyBorderView.layer.borderColor = UIColor.blueColor().CGColor

    imageView.addSubview(frameIdentifyBorderView)

enter image description here

perfect!

Upvotes: 4

PatrickNLT
PatrickNLT

Reputation: 4425

In fact, it's built-in since iOS 4 (for UIViewContentModeScaleAspectFit):

@import AVFoundation;

AVMakeRectWithAspectRatioInsideRect(imageView.image.size, imageView.bounds);

Since frame components may be not round numbers, consider wrapping the call by

CGRectIntegral(…)

See http://nshipster.com/image-resizing/ for more tricks.

Upvotes: 32

Costique
Costique

Reputation: 23722

If it's UIViewContentModeScaleAspectFit, it's something like this:

UIImageView *iv; // your image view
CGSize imageSize = iv.image.size;
CGFloat imageScale = fminf(CGRectGetWidth(iv.bounds)/imageSize.width, CGRectGetHeight(iv.bounds)/imageSize.height);
CGSize scaledImageSize = CGSizeMake(imageSize.width*imageScale, imageSize.height*imageScale);
CGRect imageFrame = CGRectMake(roundf(0.5f*(CGRectGetWidth(iv.bounds)-scaledImageSize.width)), roundf(0.5f*(CGRectGetHeight(iv.bounds)-scaledImageSize.height)), roundf(scaledImageSize.width), roundf(scaledImageSize.height));

Upvotes: 35

Related Questions