Definitive way to do rounded corners inside UITableViewCells? - iphone

So I've been all over the web, trying to figure out a definitive way to do this, and I can't seem to get it. Each of my table view cells has 3 dynamically-loaded images that I need to add rounded corners to. Right now I'm using Quartz and the layer.cornerRadius property of the ImageViews to round the corners, but of course it kills the scrolling performance of the table view.
Browsing online, I can't seem to find an answer to the performance problems. Most threads either end in suggesting the use of pre-rendered static images (not an option for me since the images are loaded dynamically, from the web) or some drawing trick that Loren Brichter came up with for Tweetie- however, the example project he posted on his blog is now a dead link, and I can't find it anywhere.
So basically, my question is how exactly should I go about accomplishing the rounded corners on elements inside a table view cell, without sacrificing performance? Thanks for any help!

Looking at the other answers it looks like you are using a lot of alpha transparency that is going to cost you a lot performance wise. You may consider revisiting that to get additional frames. One idea you may try doing is rendering the rounded image in a graphics context and using that as your cell image instead of the QuartzCore rounding.
Load the image in the imageview
Round the corners
Render the image into a graphics context
Set the imageview with the new image
Turn rounding off
Do all of this in the cellForRowAtIndexPath: method. There may be more efficiencies to be had (like caching the rendered image), but this is a way to at least test out the performance of a pre-rendered rounded image.

What about using a mask concept, and overlaying a mask UIImageView with transparent background over your dynamic images. Havent tried that, my self but it's an option.

Related

UIImageView v/s Drawing from code

I'm developing an app that must show one of three shapes(UIImageViews) depending on which button the user taps. I'm achieving this by creating different UIImageViews with three UIImages. I was wondering, is it more efficient if I draw the shapes directly from code??
BTW, the images have transparency and are 342 px x 388 px. Thanks!
It depends on the shapes. I suggest using PNG image files unless you are having particular speed issues. This lets the designers/artists customize the look easily rather than making the programmers do it in code, which is more tedious to modify.
We have some nice gradients and shadows in our application and drawing them using Quartz was pretty slow -- fine for a single screen, but too slow when animated or scrolled.

Subclassing an UIView efficiently

Guys I'm having some troubles subclassing an UIView.
I'm creating an IconView.
Simply it's a container for some other subviews.
In my IconView i have this iVar:
UIImageView _background
UIImageView _icon
UILabel _iconLabel.
When I initialize the IconView I setup this 3 iVar with images, text and some quartz effect like roundCorner and Shadow and then I add them to the self view.
Everything is Ok but if I insert some of this IconView (i.e. 10) inside an empty scrollview the scroll effect is not smooth. I tried before inserting thousand of simple UIViews in a scrollview and the scroll animation works perfectly.
With just 10 of my IconView the scroll animation works really bad.
I could approach differently retaining UIImages instead of UIImageViews and draw it inside drawRect: method but in this case I'm gonna loose Autoresizing property and Quartz effect.
Any suggests?
Thank, Gabriele.
Unfortunately, a UIScrollView gets slow pretty fast. There are a lots of posts and articles on this topic out there, like this Question and this (defect) blogpost along with it's sample code. There are also three sessions about 'Performance optimization in iOS' in the 2010's WWDC videos which I highly recommend to watch. To summarize the conclusions: Use as few subviews as you can and take special care of avoiding transparencies.
Ok, so much for the general 'Performance in ScrollViews' talk, now to your case: Having the same problem, I used all the tips from the articles and videos above and while they improved the performance, it just wasn't enough. I had, like you, used rounded corners one some images and I found out that this absolutely kills performance. Just deactivating them helped more than everything else. It's probably the same with the shadow effects.
Now, most likely, you want to keep those rounded corners. I would suggest that you create a copy of your images (or take the original, if possible) and than manipulate them directly, using those awesome classes. This way, the effects will only be applied once. It works perfectly for me. For you shadows, you can probably just create some in Photoshop and use them in a new ImageView.
If that isn't enough, you should try to cache your IconViews, like TableViewCells are cached, if you don't already do this.
The problem will probably be the Quartz shadows. They can really slow the rendering down if used a lot.
Before you write them off, you might try setting your CALayer's shouldRasterize property to YES. This makes quartz render the shadow only once and store it in a buffer. See how it goes.

implementing stretchable dialog borders in iphone sdk

I want to implement dialog borders that scale to the size I require the dialog to be. Perhaps there is a better more conventional name for this sort of thing. If there is, if someone would edit the title, that'd be great.
Anyhow, I'd like to do this so I can have dialogs of any size without the visual artifacts that come with scaling border art to small, large, or wacky unproportional dimentions. I have a few ideas on how this is done, but am not sure which is better for iphone. I have a few questions.
1) Should I make a containing view object that basically overloads its drawRect method and draws the images where they should be at their appropriate scale when the method is called, or should I main a containing view object that simply contains 8 UIImageViews? I suspect the latter approach won't work if I need to actively scale the resulting dialog class like in an animation.
1b) If overloading drawRect is the way to go, does someone have some sample code or a link to an example that demonstrates drawing an image directly from drawRect()?
2) Is it generally better to create
a) a 3 x 3 image where the segments are in their appropriate 1x1 grid of the image? If so, is it simple to draw from a portion of this image onto my target view in drawRect (if the former assumption is correct that I should use drawRect)?
b) The pieces separately in 8 different files?
UPDATE:
To clarify, the idea is to take any customized border art and be able to stretch the 2nd, 4th, 6th, and 8th cell (in a 3x3-cell grid) to form a border of any size with just those assets. Stretching just a plain image would result in distortion of the corners, so I'd like to stretch those even numbered cells as needed and tack on the corners so there is no distortion. I'd seen this done before so thought it might be a standard thing and have a standard naming to it other than what I called it.
Anyhow, I was advised that adding 8 UIImageViews to a container would not be as efficient as drawing the UIImages on the fly in drawRect so took that approach using CGContextDrawImage() after applying the necessary transformations to the context to translate and scale the Y. Because this function draws from the bottom left corner of an image but onto a top-left origined UIView, the image is upside down without the Y axis invert. I noticed the suggestion to use UIImage functions like drawAtPoint works as well and similarly but for the invert since UIImage draws in the same orientation as UIViews. I will continue my implementation with the former and see how it goes, but one other question.
Would someone happen to know which of these approaches is more efficeint, faster, etc?
I'm not sure I follow, but here's my best shot at an answer...
Using drawRect: or adding individual UIImageViews to a parent view is entirely up to you. UIImageView gives you a bit of encapsulated functionality for free, but otherwise they are the same as far as appearances go.
If you do want to go the drawRect route, you just need to use UIImage's drawAtPoint: method. Do the math for where you want it to be, and draw it. You can calculate your points based on the parent view's dimensions.
As far as scaling, it's impossible to resize these images without scaling them, so I'd plan ahead and make your originals as large or larger than you ever expect to display them.
Hope that helps a little?
Cheers
If you want a border on a dialog box, assuming the box is a UIView (or subclass), then set the layer's border properties and let the system draw the border for you.
#import <QuartzCore/QuartzCore.h>
// ...
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor whiteColor].CGColor;
view.layer.cornerRadius = 0; // 0=square corners, >0 for rounded

Changing color of part of an image

I have a png image file that is partly opaque and partly transparent. I display it in a UIImageView as a mask of sorts over another UIImageView layered behind it (as a sibling subview of a common superview). It gives me perfect borders around something painted using a finger on the lower UIImageView in my stack of UIImageViews. Perhaps there are better ways to do this, but I am new-ish, and this is the best way I came up with thus far. None the less, my app is in the App Store and now I want to enhance it to provide more images to use as the mask of sorts over the finger painting. But I don't want to bloat my bundle size by adding more static mask images as I did for the initial implementation. Not to mention I don't want to spend lots of time in photoshop making 100 masks. I'd rather programmatically change the color of the mask, without affecting the clear portion in the middle, which is not a simple regtangle or circle, but rather a complex shape. So my question is this: How can I change the colored portion of my loaded image without affecting the clear color portion in the middle? Is there a reasonably easy way to do this? Essentially I want to do what is described in this post (How would I tint an image programmatically on the iPhone?) without affecting the clear portion of my image. Thanks for any insights.
Have a look at the Tinted Image sample project. Try out the different modes until you get the effect you want.

How do I use CALayer with the iPhone?

Currently, I have a UIView subclass that "stamps" a single 2px by 2px CGLayerRef across the screen, up to 160 x 240 times.
I currently animate this by moving the UIView "up" the screen 2 pixels (actually, a UIImageView) and then drawing the next "row".
Would using multiple CALayer layers speed up performance of rendering this animation?
Are there tutorials, sample applications or code snippets for use of CALayer with the iPhone SDK?
The reason I ask is that most of the code snippets I find that demonstrate simple examples of CALayer employ method calls that do not work with the iPhone SDK. I appreciate any advice or pointers.
Okay, well, if you want something that has some good examples of CA good that draws things like that and works on the phone, I recommend the GeekGameBoard code that Jens Aflke published (it is an improved version of some Apple demo code).
Based on what you are describing I think you are doing somthing way more complicated than it needs be. My impression is you want basically a static view that you are animating by shifting its position so that it is partially off screen. If you just need to set some static content in your drawRect going through layers is not going to be faster than just calling CGFillRect() with your color. After that you could just use implicit animations and the animator proxy on UIView to move the view. I suspect you could even get rid of the custom drawRect: implementation with a patterned UIColor, but I honestly have not benchmarked the difference between the two.
What CALayer methods are you seeing that don't work on iPhone? Aside from animation features tied to CoreImage I have not noticed much that is missing. The big thing you are likely to notice is that all views are layer backed (so you do not need to do anything special to use layers, you can just grab a UIView's layer through the layer accessors methos), and the coordinate system has a top left origin.
In any event, generally having more things is slower than having fewer things. If you are just repeating the same pattern over and over again you are likely to find the best performance is implementing a custom UIView/CALayer/UIColor that knows how to draw what you want, rather than placing visually identical layers or views next to each other.
Having said that, generally layers are lighter weight than views, so if you have a lot of separate elements that you need to keep logically separated you will find that moving to layers can be a win over using views.
You might want to look at -[UIColor initWithPatternImage:] depending on exactly what you are trying to do. If you are using this two pixel pattern as a background color you could just make a UIColor that draws it and set the background.
What CALayer methods are you seeing that don't work on iPhone?
As one example, I tried implementing the grid demo here, without much luck. It looks like CAConstraintLayoutManager and CAConstraint are not available in QuartzCore.h.
In another attempt, I tried a very simple, small 20x20 CALayer object as a sublayer of my UIView's layer property, but that didn't show up.
Right now, I have a custom UIView of which I override the drawRect method. In drawRect I grab a context and render two types of CGLayerRefs:
At "off" cells I draw the background color across the entire 320x480 canvas.
At "on" cells, I either draw a single CGLayerRef across a grid of 320x480 pixels (initialization) or across a 320x2 row (animation).
During animation, I make a UIImageView clip view from 320x478 pixels, and draw a single row. This "pushes" my bitmap up the screen two pixels at a time.
Basically, I'd like to test whether or not using CALayer will accomplish two things:
Make my rendering faster, if CALayer has less overhead than what I'm doing now
Make my animation smoother, by letting me transition a layer up the screen smoothly
Unfortunately, I can't seem to get a basic CALayer working at the moment, and haven't found a good chunk of sample code to look at and play with.