21
votes

I have a UIImageView which shows an UIImage.

The UIImage may change to other UIImage in different size, and the position and the size of the UIImage inside will change according according to it.

My Problem is that i'm trying add a view that will be at the end of the UIImage (which change all the time) and all I can get is the frame of the UIImageView (which stay full screen all the time).

How can i get the "frame" of current showing UIImage ?

5
There is no direct API to get that info. You will need to calculate it yourself based on the image view's frame, the image size, and the contentMode of the image view.rmaddy
@rmaddy that's sounds like a very hard thing to tell. isn't there a way to hack it in a simpler way ?Asaf Nevo
You can use the Imageview.image.size.width/height to get the witdth and height. Though i do not know about the origin.x and y propertiesEyeball
lets start this way, please post your code showing how you load the image to the imageviewchewy

5 Answers

24
votes

The following will answer your question, assuming your UIImageView used UIViewContentModeAspectFit:

You have to regard the image sizing of the image inside UIImageView. This depends on how you set the contentMode. According your description, I assume you are using UIViewContentModeAspectFit. The resulting image will also be centered in the UIImageView so you also have to consider this for the calculation.

-(CGRect )calculateClientRectOfImageInUIImageView:(UIImageView *)imgView
{
    CGSize imgViewSize=imgView.frame.size;                  // Size of UIImageView
    CGSize imgSize=imgView.image.size;                      // Size of the image, currently displayed

    // Calculate the aspect, assuming imgView.contentMode==UIViewContentModeScaleAspectFit

    CGFloat scaleW = imgViewSize.width / imgSize.width;
    CGFloat scaleH = imgViewSize.height / imgSize.height;
    CGFloat aspect=fmin(scaleW, scaleH);

    CGRect imageRect={ {0,0} , { imgSize.width*=aspect, imgSize.height*=aspect } };

    // Note: the above is the same as :
    // CGRect imageRect=CGRectMake(0,0,imgSize.width*=aspect,imgSize.height*=aspect) I just like this notation better

    // Center image

    imageRect.origin.x=(imgViewSize.width-imageRect.size.width)/2;
    imageRect.origin.y=(imgViewSize.height-imageRect.size.height)/2;

    // Add imageView offset

    imageRect.origin.x+=imgView.frame.origin.x;
    imageRect.origin.y+=imgView.frame.origin.y;

    return(imageRect);
}

For a better illustration of the differences between the three content modes, see below:

enter image description here

24
votes

Swift 4.2 & 5.0

func calculateRectOfImageInImageView(imageView: UIImageView) -> CGRect {
        let imageViewSize = imageView.frame.size
        let imgSize = imageView.image?.size

        guard let imageSize = imgSize else {
            return CGRect.zero
        }

        let scaleWidth = imageViewSize.width / imageSize.width
        let scaleHeight = imageViewSize.height / imageSize.height
        let aspect = fmin(scaleWidth, scaleHeight)

        var imageRect = CGRect(x: 0, y: 0, width: imageSize.width * aspect, height: imageSize.height * aspect)
        // Center image
        imageRect.origin.x = (imageViewSize.width - imageRect.size.width) / 2
        imageRect.origin.y = (imageViewSize.height - imageRect.size.height) / 2

        // Add imageView offset
        imageRect.origin.x += imageView.frame.origin.x
        imageRect.origin.y += imageView.frame.origin.y

        return imageRect
    }

Swift 3.0

// MARK: - Create Rect
func calculateRectOfImageInImageView(imageView: UIImageView) -> CGRect {
    let imageViewSize = imageView.frame.size
    let imgSize = imageView.image?.size

    guard let imageSize = imgSize, imgSize != nil else {
        return CGRect.zero
    }

    let scaleWidth = imageViewSize.width / imageSize.width
    let scaleHeight = imageViewSize.height / imageSize.height
    let aspect = fmin(scaleWidth, scaleHeight)

    var imageRect = CGRect(x: 0, y: 0, width: imageSize.width * aspect, height: imageSize.height * aspect)
    // Center image
    imageRect.origin.x = (imageViewSize.width - imageRect.size.width) / 2
    imageRect.origin.y = (imageViewSize.height - imageRect.size.height) / 2

    // Add imageView offset
    imageRect.origin.x += imageView.frame.origin.x
    imageRect.origin.y += imageView.frame.origin.y

    return imageRect
}

For Swift < 3.0

Here is the above method in Swift. Again, assuming that contentMode is set to .ScaleAspectFit If there is no image on the given imageView CGRectZero will be returned.

func calculateRectOfImageInImageView(imageView: UIImageView) -> CGRect {
    let imageViewSize = imageView.frame.size
    let imgSize = imageView.image?.size

    guard let imageSize = imgSize where imgSize != nil else {
        return CGRectZero
    }

    let scaleWidth = imageViewSize.width / imageSize.width
    let scaleHeight = imageViewSize.height / imageSize.height
    let aspect = fmin(scaleWidth, scaleHeight)

    var imageRect = CGRect(x: 0, y: 0, width: imageSize.width * aspect, height: imageSize.height * aspect)
    // Center image 
    imageRect.origin.x = (imageViewSize.width - imageRect.size.width) / 2
    imageRect.origin.y = (imageViewSize.height - imageRect.size.height) / 2

    // Add imageView offset
    imageRect.origin.x += imageView.frame.origin.x
    imageRect.origin.y += imageView.frame.origin.y

    return imageRect
}
8
votes

I recommend using built in function AVMakeRectWithAspectRatio.

func AVMakeRectWithAspectRatioInsideRect(_ aspectRatio: CGSize, _ boundingRect: CGRect) -> CGRect

Parameters:

aspectRatio:
The width and height ratio (aspect ratio) you want to maintain.

boundingRect: The bounding rectangle you want to fit into.

Return Value Returns a scaled CGRect that maintains the aspect ratio specified by aspectRatio that fits within bounding Rect.

let boundingBox = AVMakeRectWithAspectRatioInsideRect(backgroundImage.size, frame)

5
votes

Based on the wonderfully simple solution from Janusz, here's what I did:

let visibleRect = AVMakeRect(aspectRatio: CGSize(width: image.size.width, height: image.size.height), insideRect: self.frame)
if visibleRect.contains(point) {
    // Do something great here...
}
3
votes

Swift 3.0

I know its quite late but might help someone in future. Its very simple and inbuilt solution provided by iOS. Just need to:

import AVFoundation
let imageRect = AVMakeRect(aspectRatio: image.size, insideRect: self.imageView.bounds)