Cocoa-Touch: When implementing drawRect, how do you redraw the transparent background? - iphone

I'm implementing a UIView's (UITableViewCell to be more exact) drawRect method.
My view has a transparent background, so when something is changed in the view, the older drawn version still remains there. So if on the first drawRect draw an "A", then a "B" on the same point, I get both of them drawn on top of each other.
How can I tell the framework to redraw the background?
(which I suppose it doesn't do because is not always needed, but in this case it badly is)
I guess what I need is the equivalent of win32's invalidateRect, however I went thru UIViews members and didn't find anything.
Btw, i've tried setNeedsDisplay, it didn't help.

I think I've used CGContextClearRect(CGContextRef context, CGRect rect) for this before.

you should set clearsContextBeforeDrawing

I wonder if, since it is your own view that is retaining the drawing, whether you yourself should erase the rect being passed in?
What happens if your background is not transparent?

It's possible having come from the Windows world that you're thinking about the problem wrong. Having also come from the Windows world, I've done the same many times myself. Why do you need to override drawRect? Whenever you do that, you are responsible to take care of everything. Is it possible to do what you are wanting another way? What are you drawing in drawRect? Can you just add sub views or sub layers to your cell instead?
BTW, are you calling [super drawRect:rect] at the beginning of your drawRect override?

I'm no longer reusing cells.
This is working for me because I always have < 20 cells in my table. I guess this is not a solution for everyone, but it's the way I'm planning to go.
Rather than have the framework create and reuse 10ish cells, I'm creating my 20 while fetching the data for them, and later at display time things go smoother because they don't need to be re-customized every time.

Related

Performance of drawRect

Hey guys just a quick question about the performance of drawRect: as I've noticed a lot of topics with people complaining about performance issues.
In my App, I need to draw ~150 squares overtop some underlaying views. Obviously this many calls isn't going to have a noticeable user difference, but I'm just wondering about the pros and cons going forward. Currently I'm debating two ways:
1) add a transparent UIView subclass on top with a custom drawRect: to facilitate the drawing
2) just add normal square subviews
As I said, using CADisplayLink there won't be any difference to the user, I'm just curious what would be more efficient? (2) is kind of a ridiculous way of doing it, adding instances with useless functionality just for appearance, but all these posts have just scared me into using drawRect. Is drawRect really that inefficient?
Thanks
Perhaps unintuitively, drawRect: isn't called for every frame. In fact, if you do nothing special in your view and your view itself doesn't change, it gets called once.
You can force it to be called by calling [myView setNeedsDisplay], but there usually is no reason to.
If you have a view with overlapping subviews, still for each of those views, including the superview, drawRect: is only called once. Then, the GPU does the compositing (blending).
A custom drawRect: is almost always slower (and harder) than just using UIKit the way it was intended, if UIKit already offers what you want to do.
Also don't fall into one of the biggest traps in software development, premature optimization. Code the most naive version, benchmark it, and if it's fast enough, it's good enough, and you can focus your energy elsewhere. Only start optimizing once you know that something is actually slow, and where and why it is.

Iphone - Drawing into a view : philosophy and interactions

I've understood that I need to subclass a UIView t be able to draw inside it.
The thing I don't understand yet, is the philosophy of the way i must be done...
Let's say I have a view controller, and depending on context, I may want to draw a line into one of the subviews it manages, or a circle, or a rect, or a processed graphic. Or lets say two points that are moving inside a view into a defined rect and that display a bigger point when they are close.
How may I subclass and define the subview to make it able to do this only into its drawRect method ?
How does the controller, that manages more than this simple UIView (let's imagine you have a view controller that manages a view inside which there are many other view, and you want to make some drawings in two of them), and that knows what is needed to be drawn into the correct view (it's a controller, isn't it ?), may interact with the views ? And when the drawing is done, how may the views interact with the controller ?
I've read many doc about drawings (apple, web, forums, tutorials, ...), but I still can't touch the philosophy of the way this must be done.
it's very simple. Make a new class, OliverView, which is a UIView. (ie, it is a subclass of UIView.) In that view, make it draw stuff in a fancy way, inside drawRect.
Now make a UIViewController, called OliverVC. In storyboard put an OliverView inside OliverVC. (beginner explanation of how to do that).
In the OliverView, have properties "hours", "minutes", "seconds".
Now, in OliverView - in the drawRect - have a fancy way to display those values. (Pie chart, glowing letters, animation - whatever you want.)
Now, up in OliverVC, do some calculations to determine the time in Zimbabwe, for example.
Once you want a time displayed, simply set those properties in OliverView - - and you are done.
Your colleague could be programming the OliverView. You need know nothing about how she is going to display the time. Conversely, your colleague need know nothing about your calculations in OliverVC..
So, it's simpleL One part has the job of displaying the data. One part has the job of coming up with the data (doing whatever sort of calculation is relevant in the app).
It's the only architecture possible in a "real time" screen device where the views can and do change at any time.
In answer to your question below: you've forgotten that quite simply, if you have a button that would be a whole separate element. (Perhaps sitting "on top of" the OliverView.) So, it's easy!
The -drawRect method in your UIView subclass defines the onscreen appearance of the view. All drawing is done in -drawRect. Your UIViewController calls methods on its UIView to tell it to draw something differently or to perform some other action.
The UIViewController manages everything to do with the view that is not inherently associated with the drawing of the content. Data associated with the view is often stored in the controller.

Any ideas on how to make a UIPickerView from scratch?

I've decided that I don't want to ever use UIPickerView again... it's completely inflexible in terms of functionality, design, and size (height). It also occasionally gets stuck between rows, and the delay that occurs between letting go of a wheel and when the delegate method is fired indicating that a new row has been selected (because of the "settling in" animation) has caused lots of problems in the context of the apps I've been working on.
That being said, the user-friendly aspects of UIPickerView are good, and I'd like to try to replicate it. I've tried to research different ways that this might be done, but without much success. Does anyone have any ideas as to what would be involved to make something similar from scratch?
I was trying to get a UITableView subclass to behave in such a way that whatever cell was currently in the middle of the table (it would change while dragging, etc.) would change its background colour to something different implying that it was "selected". As soon as the table was dragged such that the "selected" cell was no longer in the middle, the cell would go back to normal and the new middle cell would change colour. So this would be like UIPickerView in a sense that you don't have to tap on a cell; instead you just drag to have one selected by default.
I figured it should have been easy enough to intercept the "touchesMoved" method of UITableView and add some code that looped through all currently viewable cells in the table, checking to see if their frames overlapped the center point of the table, and changing their appearance accordingly (plus sending a notification to other classes as needed to indicate the "selection" change). Unfortunately, I can't get this to work, as the "touchesMoved" method doesn't get called when I drag the table. Am I missing something obvious?
Any ideas or suggestions would be very much appreciated at this point... I made an app that relied heavily on UIPickerView objects, and because of the problems I've run into with them, I'll have to abandon it unless I can figure out a way to make this work.
Thanks very much,
Chris
Remember that a UITableView is a subclass of a UIScrollView, and the UITableViewDelegate gets all the UIScrollViewDelegate method calls too. scrollViewDidScroll: sounds like it would easily fit the bill for knowing when the table view was scrolled.
As for finding which row is in the middle of the view, just use indexPathForRowAtPoint:.

UIScrollView - how to draw content on demand?

I want to create a scroll view with a massive contentSize that will display content inside it. The content will be mostly text (a few small images will be drawn for content-boundaries).
So, think like a tiled map application, but tiling labels instead of tiled images.
Performance is critical in this application, so I think I should avoid using UILabels or any UIViews at all inside the scroll view.
How can I draw these labels as the user scrolls around? Some options I've considered:
override drawRect: in the scroll view and draw everything within the window - this seems like it would be really slow. Sometimes drawRect is called with only a 1 pixel difference.
Same, but keep track of which ones I've already drawn
Draw them from the "outside" somehow, like from the scroll view delegate - I can't figure out how to use [#"mystring" drawInRect:] outside of drawRect: (context problems)
Is there something I haven't thought of? I know the scroll views were designed to be able to handle this kind of problem, but I'm not sure what the designed way is. Thanks!
The standard way to achieve this in an iPhone application is to create a normal UIScrollView that is the size you want it to be, and to populate it either directly with a CATiledLayer if you're feeling brave or with a custom UIView subclass that uses a CATiledLayer and implements - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context.
CATiledLayer provides the same experience as Safari — it's good for views that are much larger than the screen and which are expensive to render, but which you don't want to ruin the fluidity of the user experience. It'll request tiles as and when it needs them on a background thread, then fade them in (according to a fade of any length, so you can cause them to appear instantly if you desire) when they're ready. If your program really can always keep up with the scrolling and you've requested an instant appearance then there'll be no evidence that there's an asynchronous step involved.
An example people tend to point to is this one, but if you're new to implementing your own UIView subclasses then it might be worth seeing e.g. this tutorial. Then look into the + layerClass property on UIView and the various properties of CATiledLayer (which I think you'll also possibly need to subclass since + fadeDuration is a class method).

When is 'drawRect' called?

I have some custom drawing code in drawRect which also performs some calculation of sizes.
When is the earliest I can be sure that this code has been loaded, e.g. if I want to modify it's containers size accordingly?
-[NSView viewWillDraw] is a reasonable place for last minute layout.
I have some custom drawing code in drawRect which also performs some calculation of sizes.
When is the earliest I can be sure that this code has been loaded, e.g. if I want to modify it's containers size accordingly?
An object can't exist until its class is fully loaded. If you have an instance, the class that it's an instance of is completely loaded, because you wouldn't have an instance of it if it wasn't.
As for when it's called: It's called when you need to draw. This normally happens as part of the event loop, if anything has marked the view as needing display. It is possible to directly tell an NSView to display, but, as far as I can tell, this is not possible for UIViews.
So, if you need to do something to it before it gets told to, either do it immediately after creating it or, if you're about to set the view as needing display, do it before you do that.
Just before the view is displayed or when you call
[aView setNeedsDisplay];
I just created my first customView app. This was one of my questions. my drawRect method was called once upon creating my window (or recreating). And millions of time when resizing my window.