Archive for the 'ipad' category
UIButton graphics highlighting
January 31, 2011 6:54 amI have often tried to create a UIButton subclass to do something special, like draw a shadow, but couldn’t make it work. You can’t just override UIView’s drawRect: method and get the results you expect. My usual response to that is: Fine, I’ll make my button a subclass of UIControl, then.
That leaves the problem of how to highlight the button’s image when it is pressed. UIButton does a great job of this, drawing a black mask on top of the button’s image, ignoring any transparent pixels. I’ve been trying to figure out how to reproduce that effect for probably a year, I suspect, without success.
CoreGraphics is powerful. There’s pretty much nothing it can’t do. But it’s not exactly easy to work with. I have finally read enough of other people’s blog posts so that I can cobble together a solution. I’ve included a function below that inputs a UIImage object and outputs a new UIImage with a black mask drawn over it, exactly the same effect that UIButton uses.
I’ve included a screen-shot from the simulator to show what the effect looks like. On the left, you’ll see an image that is similar to the icon for the Calendar program on the iPhone. Next is that same image, highlighted by UIButton. The third image is highlighted with the function shown below. The two highlighted versions are almost exactly the same. You can tell the difference with a color-dropper tool, but I doubt you could tell them apart with the naked eye.
I know I pretty much never use code from other people’s blog posts without modifying it to suit my own uses. Assuming you’re like that as well, here’s some notes that will help you understand the code better.
The alpha value for the black mask, 0.46, was chosen because it produces results nearly identical to what UIButton does. You can make that number bigger or smaller for a lighter or darker mask.
UIGraphicsBeginImageContextWithOptions() is the best function to use to begin an image context. It will get you high-resolution graphics on the iPhone 4’s “retina display.” But that function does not exist on older versions of iOS. Therefore, we test for its existence before calling it, by checking to see if its function pointer is NULL. If so, we fall back to the older method that’s been available since the earliest iOS versions. If you don’t plan to support versions of iOS earlier than 4.0, then you can omit the availability test.
There are a couple of lines of code that transform the coordinates normally used by CoreGraphics functions to those normally used by UIKit objects. Without those two lines, the black mask would be drawn upside-down. I don’t understand this business very well. I just know the function fails without them.
The secret sauce is CGContextClipToMask(). It was easy to figure out how to draw a colored mask over an existing image, but you need this extra step to prevent the mask from being drawn over transparent pixels.
UIImage* WBHighlightImage(UIImage* image) { const CGSize size = image.size; const CGRect bnds = CGRectMake(0.0, 0.0, size.width, size.height); UIColor* colr = nil; UIImage* copy = nil; CGContextRef ctxt = NULL; // this is the mask color colr = [[[UIColor alloc] initWithWhite:0 alpha:0.46] autorelease]; // begin image context if (UIGraphicsBeginImageContextWithOptions == NULL) { UIGraphicsBeginImageContext(bnds.size); } else { UIGraphicsBeginImageContextWithOptions(bnds.size, FALSE, 0.0); } ctxt = UIGraphicsGetCurrentContext(); // transform CG* coords to UI* coords CGContextTranslateCTM(ctxt, 0.0, bnds.size.height); CGContextScaleCTM(ctxt, 1.0, -1.0); // draw original image CGContextDrawImage(ctxt, bnds, image.CGImage); // draw highlight overlay CGContextClipToMask(ctxt, bnds, image.CGImage); CGContextSetFillColorWithColor(ctxt, colr.CGColor); CGContextFillRect(ctxt, bnds); // finish image context copy = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return copy; }
Categories: cocoa, ipad, iphone, objective-c, programming
1 Comment »
iPhone and iPad SDK coexistence
February 14, 2010 7:14 amApple has released a new SDK specifically for iPad. It’s not yet ready for prime-time, so if you want to continue to develop for iPhone, you’ll need to use both the old and new SDKs for awhile. Curious about the logistics of this endeavor, I googled up this article. I dutifully followed the instructions and installed the beta 1 release in a separate dev directory. Yeah, I’m calling shenanigans. It did not work. I think it’s a bit irresponsible to post something like that without having tried it.
You can’t completely separate the two SDKs. According to the release notes, the one that is installed last is the one whose compilers will be used for both. I had other problems as well. Both the old and new device simulators were crashy. So I completely wiped both sets of dev tools and reinstalled the iPhone SDK.
Recently, Apple released beta 2 of the iPad SDK. They may have fixed the problems I experienced before, but I’m not taking any more chances. This time, I got myself an external Firewire hard drive. USB 2.0 would also work, but I prefer Firewire for a possibly frivolous reason: I have so many USB devices that it’s difficult to find a place to plug in a new one, but I have two Firewire ports on the back of my Cinema Display that are otherwise unused.
This next part is important. You’re going to need to boot off this drive, so its partition map scheme must be set to “GUID Partition Table.” If it isn’t, you should reinitialize it so that it is. On the Mac, you use the Disk Utility program for this. It doesn’t create GUID partition tables by default, so you have to press the button that says “Options…” and change it.
Next, use a program like Carbon Copy Cloner to make a copy of your primary hard drive onto the external drive. Finally, in System Preferences, pick “Startup Disk,” select your external hard drive, and reboot. Now install the new iPad SDK. It will be copied onto your external disk, leaving your primary disk alone. This way, the two SDKs won’t butt heads with each other.
It’s a shame that Apple is making us solve a software problem with hardware, but this is the sort of inconvenience you have to put up with if you want to live on the bleeding edge. I can’t even remember the last time I had to use the Startup Disk pref pane before this. It’s been years, surely. This reminds me of when I used to work at Be, and we had a new version of BeOS to install every couple of weeks.
Categories: cocoa, ipad, iphone, programming
Comments Off


