Friday, March 26, 2010

Improved Irregular Shape UIButton

I took some of the feedback and improved the UIButton subclass from my last post. I implemented a cache for the alpha data and also incorporates changes based on Alfons Hoogervorst's modifications to my original UIImage category.

You can find the new and improved version of the irregular shaped UIButton code here.


David Gregory said...

Jeff, not sure whether to leave this comment on your blog, or Alfons' blog.

There's two more things you could do to improve this, if RAM is your concern.

a) Convert from an alpha mask with full transparency to 1 bit per pixel. There not really any reason to store "shades of transparency" for hit testing - you either hit it or you don't.
b) Implement run-length-by-line encoding. It's incredibly easy to skip to the "Y" record of an RLLE image, and then find the "X" pixel within that line. Not quite as quick as an array lookup.

Alfons said...

Great suggestion, yes: just the bitmask would be better. (And in a preprocessing step, you could just generate the bitmask and include them as a seperate file in your resources.)
It's a bit more work though; my point was to show how to get the interesting bits using just CG while using less memory.

Jeff LaMarche said...


That's a great idea, actually. I might take a look at implementing a), and if I'm feeling ambitious, I might look at b), though I have to admit that in my experimentation so far on the device, I haven't seen any performance issues with this version. Then again, I'm using a test scaffold without very much going on.

Thanks for the suggestion.


Natan said...

Hi there,
All different classes for non-rect shaped buttons seem to be having trouble handling touches at landscape mode (right). Everything seems fine on the iPad though as it has a different touch event scheme...
On the iPhone, your demos work kinda well. But as soon as even the demo is turned to landscape mode, the touches start acting very weird.
I've trying tracking the cause of the error, and I though of coordinate systems, but both are at the lower left side of the screen (origin).

Anyone had any experiences with this?
Thanks in advance for your time and help,
~ Natanavra.

Howard Katz said...

Jeff, Don't you need to do a calloc() rather than a malloc() in your original CGBitmapContextCreate() function? If you don't do the former, existing bits in the malloc'ed memory can make an unwanted pixel contribution to the bitmap you're creating.


Maffyoo said...

in the hit test method there is only a check made for point.x > width || point.y > height if the button is hosted in another view and is offset in either x or why (frame.origin.x or y > 0) then the hit test will still fire even when the point is to the left or above the button. wouldnt it be better to also override pointInside:withEvent and do a straighforward check for CGRectContainsPoint using the bounds of the button, that way, no matter where the Button is located in another view it will only check alpha when inside the bounding rect, and it will remove the incomplete test for hit location from the hitTest (and also ensure that we are using the correct mechanism for checking that the point is inside the button before checking alpha??

damiangriffin said...

Leaking Memory!!!

I found this piece of code to be incredibly useful as I have adapted to check to see if there are any pixels remaining in an image I am drawing onto. Could have never figured it out without this. The only problem I have is that the code as it stands leaks memory pretty bad.

It probably doesn't show up much with one touch or button press, but repeated taps (As in my app where I am testing to see if there are any pixels remaining in the contextRef) really show up. You can see the leak pretty well by using the memory monitor in Instruments.

I think part of the problem is the deallocation of the bitmapData. I don't think I am wise enough to figure out where this is supposed to be done. I know that I can slow the leak by using:

return [NSData dataWithBytesNoCopy:data length:dataSize freeWhenDone:YES];

instead of:

return [NSData dataWithBytes:data length:dataSize];

The weird thing is when I use NSData dataWithBytesNoCopy I lose access to the buffer in the iPhone Simulator although It works OK in on the actual device. I think that may be an unfortunate bug with dataWithBytes or something.

I think there must be a better way of making sure that the original void * bitmapData that is malloc'd is released.

Any thoughts?


Comptrol said...

@damiangriffin, yes it leaks. you should add the following line ARGBData: 's end
NSData* dataShort=[NSData dataWithBytes:data length:dataSize];
return dataShort;

Ella said...

@Comptrol - I have been having problems with this code crashing my application. It works fine in the simulator but crashes every time when running on the device.

I added the code you just suggested, but does anyone have any tips on how to stop it crashing? There must be some serious leaks I think?

Comptrol said...

@Ella, I didn't test it on the device unfortunately. Can you give a try refactored version of this post here:
and tell me if it works without crashing on the device

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels

healthpharmacyrx1 said...

Order cialis
achat xenical france
augmentin Kaufen
kamagra oral jelly Kaufen
cialis soft Online Rezeptfrei
kamagra oral jelly Rezeptfrei
Achat strattera Sans Ordonnance
lioresal Prix en France
acheter propecia en france
minocin Rezeptfrei

Doug said...

I've downloaded this and it works great. But when I replace the button images with my own it doesn't work and says its transparent everywhere I touch on the button. Is there anything special I should be doing in photoshop when making the images to make them work? Thanks

mihaiserban2 said...

Has anyone tried with retina images?
Shouldn't the bpr = bpp * width * [[UIScreen mainScreen] scale] ?

I seem to have troubles with my retina images, maybe someone has an idea..