Thanks to Mattt Thompson’s great NSHipster blog, a lot of folks are now “hip” to some pretty obscure stuff in Cocoa and Objective-C. It’s a great blog. Go read it.
It’s not always completely obvious how to use the new tools he highlights though. I found myself reading his article on CGGeometry, utterly surprised by the existence of all those useful convenience functions. But if you’re already sticking numbers into CGRectMake
(as I have been doing for forever), then why would you need functions like CGRectOffset
, CGRectInset
, and CGRectDivide
?
Simple. Don’t use CGRectMake
. Instead, keep track of a working rectangle.
For example, let’s say you’re trying to lay out a tableview cell.
- (void) layoutSubviews {
[super layoutSubviews];
CGRect workingRect = self.contentView.bounds;
This workingRect
variable is your home base. It represents the part of your view that hasn’t been sliced up yet. Let’s say you want to pad everything by a few pixels.
workingRect = CGRectInset(workingRect, 2, 2);
Bam. Done. You want to lay out your imageView
, textLabel
, and detailTextLabel
, so set up some variables.
CGRect imageRect = CGRectZero, textRect = CGRectZero, detailTextRect = CGRectZero;
Okay, time to use the coolest of the tools. CGRectDivide
takes a rect, an amount, and an edge, and “returns” a slice and a remainder.
CGRectDivide (CGRect rect, CGRect *slice, CGRect *remainder, CGFloat amount, CGRectEdge edge);
Let’s assume you’re lazily loading your subviews, so check if you’ve got an image and divide your workingRect
up. The crucial thing here is to pass your workingRect
for your remainder
, so that you can keep working with it. Cut off a square from the left side with a square for the imageView
.
if (_imageView.image) {
CGRectDivide(workingRect, &imageRect, &workingRect, workingRect.size.height, CGRectMinXEdge);
}
Boom. You have an imageRect
now, and you can continue to work with your workingRect
. Do the same with your detailTextLabel
.
if (_detailTextLabel.text.length) {
CGRectDivide(workingRect, &detailTextRect, &workingRect, workingRect.size.height/2, CGRectMaxYEdge);
}
The leftover, whatever it is, is the textRect
.
textRect = workingRect;
Now you can just set your rects to the frames of your objects!
self.imageView.frame = imageRect;
self.textLabel.frame = textRect;
self.detailTextLabel.frame = detailTextRect;
}
You’re done. Easy like Sunday morning, and a lot more readable than a half dozen CGRectMake
calls.