问题
I am trying to set a custom UIView class's background color. The class also does quartz drawing in the drawRect:
method.
Since background color change does not take place until the next redraw of the view, I change the UIView's backgroundColor
property before calling setNeedsDisplay
. I have set a UIActivityIndicatorView
to animate while the view is redrawing.
self.backgroundColor = theColor;
[indicator startAnimating];
[self performSelectorInBackground:@selector(setNeedsDisplay) withObject:nil];
The indicator is stopped at the end of setNeedsDisplay
. theColor
will change every time I need to call this.
Let's say I have a time consuming setNeedsDisplay
process. I would like to set the background and keep the indicator animation. Currently, changing backgroundColor
calls setNeedsDisplay
but doesn't even change the backgroundColor until the performSelectorInBackground
method runs! Therefore my app hangs and no indicator is ever animated.
How do I deal with this ordering problem? Thanks.
Edit: I meant that my drawrect:
may be time consuming.
回答1:
Let's say I have a time consuming setNeedsDisplay process
Let's not. You have no business overriding setNeedsDisplay
. I am not at all clear on what you're ultimately trying to accomplish but this entire question seems to be a misunderstanding of how to draw. When you call setNeedsDisplay
(which, as you've been told, you must do in the main thread), that's that; you stand out of the way, and when the redraw moment comes, your view's drawRect:
is called. That's drawing.
If the problem is simply that the activity indicator never gets going, that's because you never give it a chance. It too is not going to start going until the redraw moment. But you are stopping the activity indicator before the redraw moment even comes! So obviously you'll never see it go.
The way to start an activity indicator visibly before the next thing you do is to step out to the main thread after the next redraw moment. This is called "delayed performance". Example:
self.backgroundColor = theColor;
[indicator startAnimating];
double delayInSeconds = 0.1;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// do something further, e.g. call setNeedsDisplay
};
You could extend that example by calling dispatch_after
yet again to stop the indicator after the next redraw moment.
I must impress upon you, however, that if the mere act of drawing takes so long that you need an activity indicator to cover it, you're drawing wrong. Your act of drawing must be very very fast. You might want to watch the WWDC 2012 video on this very topic; it gives excellent tips on how to draw efficiently.
回答2:
You can update UI only on Main thread, not in backgroung
Try to use another subview with activity indicator, put in on before redraw and remove from superview after
来源:https://stackoverflow.com/questions/15047346/set-uiview-backgroundcolor-with-drawrect