How to get the displayed image frame from UIImageV

2019-01-13 13:56发布

问题:

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.

回答1:

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));


回答2:

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.



回答3:

Use this api from AVFoundation
#import <AVFoundation/AVFoundation.h> CGRect imageRect = AVMakeRectWithAspectRatioInsideRect(imageView.image.size, imageView.bounds);



回答4:

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

func getImageFrameInImageView(imageView : UIImageView) -> CGRect {
    /*
    by 徐明刚, ericxu1983@163.com
    算法:
        设高宽比 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)

perfect!



回答5:

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()
    }
}