Search code examples
iosperformanceuiimagedrawrect

Rounded Avatar Images on iOS and performance issues


Is there any way to draw rounded UIImages without doing any of the following?

  1. Blending (Red in Core Animation Instruments)
  2. Offscreen Rendering (Yellow in Core Animation Instruments)
  3. drawRect

I've tried

  1. drawRect with clipping path. This is just too slow. (see: http://developer.apple.com/library/ios/#qa/qa1708/_index.html)
  2. CALayer contents with a maskLayer. This introduces offscreen rendering.
  3. UIImageView and setting cornerRadius and masksToBounds. This has the same effect as #2.

My last resort would be to modify the images directly. Any suggestions?


Solution

  • I use a variation of blog.sallarp.com's rounded corners algorithm. I modified mine to only round certain corners, and it's a category for seamless integration, but that link gives you the basic idea. I assume this might qualify as "offscreen rendering", one of your rejected techniques, but I'm not entirely sure. I've never seen any observable performance issue, but maybe you have some extraordinary situation.

    Could you overlay an imageview of just corners on top of your imageview to give the appearance of rounded corners?

    Or, if you concerned about the performance hit resulting from rounding corners, why don't you have your app save a copy of the image with its rounded corners, that way you only get the performance hit the first time? It's equivalent to your notion of "modify the image directly", but do it just-in-time.

    Update:

    Bottom line, I don't know of any other solutions (short of my kludgy idea, point #2 below). But I did some experimentation (because I'm dealing with a similar problem) and came to the following conclusions:

    1. If you have a rounding performance on a 3GS or later device, the problem may not be in the rounding of corners. I found that while it had a material impact on UI on 3G, on the 3GS it was barely noticeable, and on later devices it was imperceivable. If you're seeing a performance problem from rounded corners, make sure it's the rounding and not something else. I found that if I did just-in-time rounding of corners on previously cached images, the rounding had a negligible impact. (And when I did the rounding prior to caching, the UI was smooth as silk.)

    2. An alternative to masking would be to create an image which is an inversion of the rounded corners (i.e. it matches the background in the corners, transparent where you want the image to show through), and then put this image in front of your tableviewcell's image. I found that, for this to work, I had to use a custom cell (e.g. create my own main image view control, my own labels, plus this corner mask image view control), but it definitely was better than just-in-time invocation of the corner rounding algorithm. This might not work well if you're trying to round the corners in a grouped table, but it's a cute little hack if you simply want the appearance of rounded corners without actually rounding them.

    3. If you're rounding corners because you're using a grouped tableview and you don't like the image spilling over the rounded corner, you can simply round the upper left corner of the first row's image and the lower left corner of the last image. This will reduce the invocations of the corner rounding logic. It also looks nice.

    4. I know you didn't ask about this, but other possible performance issues regarding images in tableviews include:

      • If you're using something like imageWithContentsOfFile (which doesn't cache) in cellForRowAtIndexPath, you'll definitely see performance problem. If you can't take advantage of the imageNamed caching (and some guys complain about it, anyway), you could cache your images yourself, either just-in-time or preloading them in advance on secondary thread. If your tableview references previously loaded images and you'll see huge performance improvement, at which point rounding of corners may or may not still be an issue.

      • Other sources of performance problems include using an image that isn't optimally sized for your tableview's imageview. A large image had a dramatic impact on performance.

    5. Bottom line,

      • Before you kill yourself here, make sure rounding is the only performance problem. This is especially true if you're seeing the problem on contemporary hardware, because in my experience the impact was negligible. Plus, it would be a shame to loose too much sleep over this, when a broader solution would be better. Using images that are not size-optimized thumbnails, failure to cache images, etc., will all have dramatic impact on performance.

      • If at all possible, round the corners of the images in advance and the UI will be best, and the view controller code will be nice and simple.

      • If you can't do it in advance (because you're downloading the images realtime, for example) you can try the corner masking image trick, but this will only work in certain situations (though a non-grouped tableview is one of them).

      • If you have to round corners as the UI is going, do the corner rounding in a separate queue and don't block the UI.