Created
October 7, 2013 21:05
-
-
Save lanephillips/6874933 to your computer and use it in GitHub Desktop.
Objective-C code to fit a CGRect inside or outside another CGRect while maintaining aspect ratio. The fitted rectangle is centered on the target rectangle.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CGFloat ScaleToAspectFitRectInRect(CGRect rfit, CGRect rtarget) | |
{ | |
// first try to match width | |
CGFloat s = CGRectGetWidth(rtarget) / CGRectGetWidth(rfit); | |
// if we scale the height to make the widths equal, does it still fit? | |
if (CGRectGetHeight(rfit) * s <= CGRectGetHeight(rtarget)) { | |
return s; | |
} | |
// no, match height instead | |
return CGRectGetHeight(rtarget) / CGRectGetHeight(rfit); | |
} | |
CGRect AspectFitRectInRect(CGRect rfit, CGRect rtarget) | |
{ | |
CGFloat s = ScaleToAspectFitRectInRect(rfit, rtarget); | |
CGFloat w = CGRectGetWidth(rfit) * s; | |
CGFloat h = CGRectGetHeight(rfit) * s; | |
CGFloat x = CGRectGetMidX(rtarget) - w / 2; | |
CGFloat y = CGRectGetMidY(rtarget) - h / 2; | |
return CGRectMake(x, y, w, h); | |
} | |
CGFloat ScaleToAspectFitRectAroundRect(CGRect rfit, CGRect rtarget) | |
{ | |
// fit in the target inside the rectangle instead, and take the reciprocal | |
return 1 / ScaleToAspectFitRectInRect(rtarget, rfit); | |
} | |
CGRect AspectFitRectAroundRect(CGRect rfit, CGRect rtarget) | |
{ | |
CGFloat s = ScaleToAspectFitRectAroundRect(rfit, rtarget); | |
CGFloat w = CGRectGetWidth(rfit) * s; | |
CGFloat h = CGRectGetHeight(rfit) * s; | |
CGFloat x = CGRectGetMidX(rtarget) - w / 2; | |
CGFloat y = CGRectGetMidY(rtarget) - h / 2; | |
return CGRectMake(x, y, w, h); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The AspectFitRectInRect(_, _) function behave closely to AVFoundation's AVMakeRectWithAspectRatioInsideRect() and has the same problem with images that has a close enough size.
For example, a (0, 0, 750, 1334) in a (0, 0, 1080, 1920) rectangle becomes a (0.26986506746618488, -1.1368683772161603e-13, 1079.4602698650676, 1920.0000000000002), which is close but not in a 1080 1920 rect -- especially when you try to get a CGRectIntegral() on it: (0, -1, 1080, 1921).
I believe the problem is with the approximation inherent to the CGFloat returned by the scaleToAspectFit(). Still, I'm pretty sure your solution will be enough for 99.9% of users, thanks for providing it.
I fix that little problem by not using the approx in the computation of the major dimension (the Height in the exemple) but by setting it directly to the major dimension of the target. Main con, the resulting rectangle ratio is not the same as the original.