Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aspect fit programmatically in iOS?

I want to insert one view into another with aspect fit option. But I can't just set contentMode for some reasons.

Could you provide a solution via resizing of the inner CGRect according to the outer CGRect?

And yes, there are a lot of similar questions but no one provides such solution.

like image 950
Vyachaslav Gerchicov Avatar asked Feb 07 '23 17:02

Vyachaslav Gerchicov


1 Answers

I wrote a function that should achieve what you desire.

It will return the CGRect of a given innerRect, after scaling it to fit within a given outerRect, while maintaining aspect ratio. The innerRect will be centered within the outerRect.

static inline CGRect aspectFitRect(CGRect outerRect, CGRect innerRect) {

    // the width and height ratios of the rects
    CGFloat wRatio = outerRect.size.width/innerRect.size.width;
    CGFloat hRatio = outerRect.size.height/innerRect.size.height;

    // calculate scaling ratio based on the smallest ratio.
    CGFloat ratio = (wRatio < hRatio)? wRatio:hRatio;

    // The x-offset of the inner rect as it gets centered
    CGFloat xOffset = (outerRect.size.width-(innerRect.size.width*ratio))*0.5;

    // The y-offset of the inner rect as it gets centered
    CGFloat yOffset = (outerRect.size.height-(innerRect.size.height*ratio))*0.5;

    // aspect fitted origin and size
    CGPoint innerRectOrigin = {xOffset+outerRect.origin.x, yOffset+outerRect.origin.y};
    CGSize innerRectSize = {innerRect.size.width*ratio, innerRect.size.height*ratio};

    return (CGRect){innerRectOrigin, innerRectSize};
}

You can then use this like so:

// outer rect
CGRect outerRect = CGRectMake(0, 100, self.view.bounds.size.width, 500);

// outer rect's view
UIView* v = [[UIView alloc] initWithFrame:outerRect];
v.backgroundColor = [UIColor greenColor];
[self.view addSubview:v];

// inner rect
CGRect innerRect = CGRectMake(0, 0, self.view.bounds.size.width*2, 500);
CGRect scaledInnerRect = aspectFitRect(v.bounds, innerRect);

// inner rect's view
UIView* v1 = [[UIView alloc] initWithFrame:scaledInnerRect];
v1.backgroundColor = [UIColor redColor];
[v addSubview:v1];

In this case, the innerRect is too wide for the outerRect, so it will be scaled according to it's width.

enter image description here

Here, the red area is the innerRect and the green area is the outerRect. They both originally had the same height, but after being scaled down (as it was 2x as wide), the innerRect now has half the height of the outerRect.

Here the innerRect is added as a subview to the outerRect. If you want to add them to the same superview, you can pass the outerRect's frame into the function, rather than the bounds.

like image 176
Hamish Avatar answered Feb 13 '23 07:02

Hamish