I'm designing whole UI using storyboard and all is well but for table view cells it seems to be too much. Get's crowded in designer and views can vary good deal which calls for many outlets.
I decided to custom draw them. I understand process of doing it but 2 things bother me:
Performance. Will custom-drawn cells be slower than storyboarded ones?
Reuse. I understand how reuse works and it seems that completely "erasing" contents and re-drawing might be slower than just creating new cell every time. Is that true?
If you look at design - to me it seems to be easer to write and maintain complete drawing through the code because of font backgrounds, colors, lines, etc.
Related
Are there known and proven ways to manage memory with scrolling components like tables or grids other than recycling cells as is used in Cocoa? The sequence of calculations and datasource/delegation calls needed to make this way of laying out views works but also makes coordinating complex animations with the cells and a scroll view error prone as you have to pay careful attention to the sequence of calls as it reloads data, scrolls to an offset and other mechanisms of the layout that affect the target frame of your animations. I am looking for a more declarative approach to providing content to the scroll view and having it figure out a smart way to manage it's memory as is done by a browser when you load the DOM with a long vertical layout of pictures.
I found it easier to create my own custom layout classes that only do layout on my views and not to impose an elaborate protocol such as NSTableViewDataSource and the like that makes animation difficult to program. I like to know exactly where my views are at all times, the complete hierarchy of each view and I don't like to keep a model in sync with my views so I store data on the views themselves. In my mind the objects on screen are the one and only objects I like to orchestrate as a programmer. I want direct declarative control over them kind of like a game programer. By subclassing a scroll view directly and following very simple layout rules outside of the normal layoutSubviews methods of Cocoa to avoid surprise layouts, I was able to control my animations better and do more complex and fluid animations. Hope this inspires someone to do the same.
What I am trying to do is to have many small rectangles on the screen (up to several thousand) which move randomly.
I have the mechanics behind this figured out (in terms of determining the coordinates for the movement), but I can't figure out the best way to draw the shapes or model their movement.
A couple strategies I have tried have been, first, to subclass NSView (this is on the Mac) and create thousands of these. I then change their drawRect: function in order to draw a square inside of themselves. Then it is pretty simple to just change their locations to move them around. However, with several thousand allocated instances of these, performance is obviously terrible.
I tried a less object-oriented route also, just using NSRectFill to draw the thousands of rectangles. However, I had trouble implementing the movement I needed with this, though it was blazing fast.
Does anyone have any suggestions on how I could successfully create this animation?
Layers and Core Animation are the best approach for the platform.
Several thousand rectangles may be too much for CoreAnimation. You should consider using OpenGL.
I just wanted to know how you could implement a bookcase, like in iBooks, into your iPhone app.
I presume you would need to use a UIScrollView, but then I read somewhere that you need to use a UITableView. Which is it?!
You'd use code that others have already written, such as AQGridView.
I'm not sure if there's a better way, but you could create multiple small views or images (these would represent each book) then add these small views/images to the subview of a larger view in a linear format (leaving a space between each element). Then just set the background of your larger view as an image of a bookcase. Sorry I don't know of a better way.
And for the above solution I would use a UIScrollView.
You can implement it anyway you like, but it seems to me that a UITableView would be the easiest (which will scroll anyway). All of the magic will happen in your UITableViewDataSource, which is where you will decide what books are placed on what row.
Once you have decided which books to display you will have create a custom tableview cell that draws the appropriate objects.
To be honest, while not too difficult of a task, it will take a lot of effort to get looking right. If you are not comfortable with custom drawing then be prepared to spend time learning about the various image/graphic APIs.
I have a simple App that displays a list of items using NSTableView. There are usually about 15-25 items in the list, and the table has 10 columns, all but one of which are text (the other's an icon.) There are simple data transformers on a couple of the columns. So nothing taxing; you'd expect it to run just fine.
And as it stands, it is; the app is responsive and everything draws pretty much instantly. Scrolling, changing column sizes, resizing the window; whatever you do the redraws keep up with the mouse-pointer.
Tonight, I thought I'd try adding a little visual flair to the app with Core Animation (which I've never used before,) but I've found that if anything above the NSTableView in the hierarchy is set 'Wants Core Animation Layer,' then the NSTableView redraws go to hell. Scrolling is usually fine, but resizing columns or the window causes it to pick up an effect like texture tearing, where some of the rows have the new size, and some have the old one, and everything flickers horribly. It looks terrible. Basically it looks like what you'd expect if rendering the individual rows or columns was taking a long time.
I've put it through Shark and, sure enough, it looks like it's spending most of its time drawing the text in the cells; what I don't understand is why that should take longer when there's a Core Animation layer involved than when there isn't - and quite noticeably longer at that.
Has anyone got any ideas? Is there any Core Animation initialisation or config I've missed or something (I've literally just ticked the "Wants Core Animation Layer" box in IB)?
Cheers,
Will
I know that the CGContext cannot call it to draw directly, and it needs to fill the drawing logic in the drawInContext, and call the CGContext to draw using "setNeedsDisplay", so, I designed a cmd to execute, but it cause some problems... like this :
Why I can't draw in a loop? (Using UIView in iPhone)
I think the CGContext is very different from my previous programming experience....(I used HTML5 canvas, that allow me add more details, after I draw, so do the Java Swing)
Actually, I want to know what is the suitable to implement these kind of thing in Apples' programmer mind. Thz.
There are three approaches to what you're asking. You can draw everything in drawRect:, you can manage multiple layers, or you can draw in an image. Each has advantages, but first you need to think correctly about the problem so that you don't destroy performance.
Drawing happens constantly. Every time anything changes, there may be quite a lot of drawing that has to be done. Not the whole screen usually, but still a lot of drawing. Since drawRect: and drawInContext: can be called many times, they need to be efficient. That means that you don't want to do a lot of expensive calculations, and you don't want to do a lot of useless drawing. "Useless" means "won't actually be displayed because it's off screen or obscured by other drawing."
So in the usual case, you put your actual drawing code in drawRect:, but you do all your calculations elsewhere, generally when your data changes. For example, you read your files, figure out your coordinates, create CGPaths, etc whenever your data changes (which should be much less frequent then drawing). You save all the results into ivars, and then in drawRect: you just draw the final result. So in your loop example, you would probably have an NSArray of images in your view object, and in drawRect: you would draw them all in order.
Another approach is to create a separate layer for each image, set the image as the content, and then attach the layer to the view. You're done at that point. There is no more drawing code you need to write. Quartz handles layers very efficiently, so this can be a very good solution to a wide variety of problems.
Finally, you can composite everything into an image, and then stick that image in an image view, or draw the image directly in the view, or attach the image to a layer. This is a good solution if you have very complicated drawing (particularly using CGPath). This can be expensive if you're constantly changing things, since you have to create a new image context, draw the old image into the new context, draw on top of it, and then create a new image from the context. But it's good for a complicated drawing that doesn't change often.
But you're correct, CGContext is not like a canvas. It needs to be redrawn every draw cycle. You can do that yourself, or you can use another view object (like UIImageView) to do it for you. But it has to be done one way or another.