I have an app that only needs to refresh the draw when panning on the screen is detected. For that reason I don't do the rendering in the drawInMTKView method, instead I have a method that is triggered when panning is detected and I do the required encoding there.
How can I turn off the framerate (and with it the automatic calls on drawInMTKView)?
You can still do your rendering on-demand in drawInMTKView: by setting the view's paused and enableSetNeedsDisplay properties both to true. Then, whenever you call the setNeedsDisplay method on the view, the draw method will be called as part of the ordinary display update loop.
The property enableSetNeedsDisplay controls the behaviour of the view delegate. Set it to NO to avoid the delegate being triggered by setNeedsDisplay.
Set the paused property to YES to avoid internal the callback triggered by internal timer.
mtkView.enableSetNeedsDisplay = NO;
mtkView.paused = YES;
When you want to draw, call the draw method. This will call drawInMTKView:
[mtkView draw];
Related
For my custom UIView I've overriden touchesBegan method. What I told it to do is to change its' layer's background color:
dispatch_async(dispatch_get_main_queue()){
self.layer.backgroundColor = clr_someCGColor
}
It acts weird. If I quickly tap the view while in Landscape it does everything perfectly well, but if I do this in Portrait, I have to hold it for some time to see the result, however the touchesEnded method is called right away, if I quickly tap. What could be the reason, causing the delay in Portrait?
Remove the dispatch_async wrapper. All it does is cause a delay (we can't execute on the main thread until, as you rightly say, the tap ends and touchesEnded has come and gone). You are already on the main thread, in touchesBegan, so there is no need for this extra delay.
Even better, use a tap gesture recognizer.
I'm making an animation in a CALayer that needs to update smoothly over time. I tried the following approaches:
CADisplayLink for iOS, CVDisplayLink for OS X, plus calling setNeedsDisplay from the callback
CABasicAnimation for a custom displayTime property, with fromValue=0, toValue=1, duration=1, repeatCount=HUGE_VALF, cumulative=YES, and needsDisplayForKey:#"displayTime" returning YES.
These both work to draw the animation, but I'm not sure which is better. Does Core Animation internally use a display link for updating animations?
Furthermore, neither of these allow me to know when the layer comes onscreen or is offscreen. Even the animation continues to run when the NSWindow is closed (-drawInContext: is continuously called). The kCAOnOrderOut action is not triggered, nor is -setHidden: called. How can the layer tell when it is on or offscreen?
In my case, the drawRect: will not be called immediately after every single setNeedsDisplay is called. For example, I think the following code is same as my case.
for (int i = 0; i < 100; ++i)
{
[self setNeedsDisplay];
}
From the documentation:
When the actual content of your view changes, it is your responsibility to notify the system that your view needs to be redrawn. You do this by calling your view’s setNeedsDisplay or setNeedsDisplayInRect: method of the view. These methods let the system know that it should update the view during the next drawing cycle. Because it waits until the next drawing cycle to update the view, you can call these methods on multiple views to update them at the same time.
drawRect: will only be called in time for the next frame to be drawn, which means your entire loop will result in drawRect: only being called once at the next rendering iteration. This saves unnecessary computation as it avoids drawing frames that will never be displayed on the screen. It also lets you make multiple changes in separate places in your code, each time notifying the view that a refresh is needed, without losing performance, since calling setNeedsDisplay only tells the drawing system that a redraw is needed in the next frame; it doesn't force the immediate rendering of a frame that might never be displayed on the screen.
setNeedsDisplay only marks the view as needing to be displayed again. The actual drawing call is done in the next runloop iteration of the main thread, once. This allows the drawing system to do some optimizations and "combine" repeated calls to setNeedsDisplay.
I'm using this to move my image:
meteorDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(moveImage:)];
Here is my moveImage: method:
-(void) moveImage:(CADisplayLink *)sender{
CGPoint img;
imgLocation = imgImageView.center;
if (img < 100) {
img.y++;
}
else{
imgLocation.y = 0;
}
imgImageView.center = imgLocation;
}
This updates the location of my image on screen no matter what. Why does setNeedsDisplay have no effect here? What is the point of setNeedsDisplay?
I assume imgImageView is an instance of UIImageView. If it's not an instance of UIImageView, edit your question to tell us what it is.
Changing the center property of a view never requires your app to redraw the view. The display server (which is a separate process named backboardd in iOS 6 and springboard in earlier versions) has a copy of your view's pixel data already. When you change a view's center, the view just informs the display server of its new position, and the display server copies the view's pixel data to the appropriate parts of the screen.
Thus changing the center property of a view never requires you to send setNeedsDisplay.
More specifically, UIImageView doesn't even implement drawRect:. Instead, UIImageView just sends its image's pixel data to the display server when you set its image. So even if you send setNeedsDisplay to a UIImageView, it still won't run any drawRect: method.
By the way, you can do this in your own UIView subclasses too, by setting self.layer.contents to a CGImageRef instead of implementing drawRect:. You will need to #import <QuartzCore/QuartzCore.h> to do this. Of course, UIImageView does other things too, like handling animated and resizable images.
When you set properties that affect the layout of an object, setNeedsDisplay will be called internally. You need to call it yourself for custom properties, etc, that don't automatically call it.
setNeedsDisplay only applies to the contents of a layer or view. I.e., if the contents of a view has changed and needs to be redrawn, you would use setNeedsDisplay to tell the view that it needs to be redrawn and that would trigger its drawRect method.
Transformations on a view, such as position, scale, and rotation, etc., are handled directly by the GPU and do not require the view to be redrawn; therefore, setNeedsDisplay does not apply when you're simply moving or transforming a view.
When creating an iOS app, I'm confused as to when exactly I need to call setNeedsDisplay? I know that it has something to do with updating/redrawing the UI; however, do I need to call this every time I change any of my views?
For example, do I need to call it:
After programatically changing the text in a text field
When changing the background of a view?
When I make changes in viewDidLoad?
How about in viewDidAppear?
Could someone give me some general guidelines regarding when to use this method?
You should only be calling setNeedsDisplay if you override drawRect in a subclass of UIView which is basically a custom view drawing something on the screen, like lines, images, or shapes like a rectangle.
So you should call setNeedsDisplay when you make changes to few variables on which this drawing depends and for view to represent that change , you need to call this method which internally will give a call to drawRect and redraw the components.
When you add an imageView or a UIButton as a subview or make changes to any subview, you need not call this method.
Example:
You have a view that shows a moving circle, either you touch and move it, or may be timer based animation.
Now for this, you will need a custom view that draws a circle at given center and with given radius.
These are kept as instance variables which are modified to move the circle by changing its center or make it bigger by increasing radius of it.
Now in this case either you will modify these variables(centre or radius) in a loop and timer Or may be by your fingers in touchesEnded and touchesMoved methods.
To reflect the change in this property you need to redraw this view for which you will call setNeedsDisplay.
You only really need to call -setNeedsDisplay on UIView subclasses that draw their contents with -drawRect:.
For labels and other standard controls, changing the text will automatically cause the label to redraw so you don't need to do this yourself.
setNeedsDisplay: should be called when you want to refresh your view explicitly. It just sets an internal flag, and the iOS UI system will call drawRect: at an appropriate time later.
It sounds like it should be always called when you updating any property which may change the presentation. But it's not. Almost all the standard UI controls already handled that. I believe whenever you modify the properties of standard UI components (views), setNeedsDisplay: would be triggered internally, and the affected region will be redrawn. (In all the situations you listed)
However, if you create your own view, implement its own drawRect:, and want to update that when something has been changed, you must call setNeedsDisplay: explicitly.
I think #Amogh Talpallikar make it clear. And I just wanna discuss one thing more.
In the fact that, you should avoid override drawRectunless you really need it because it can cause bad performance. You can refer this https://yalantis.com/blog/mastering-uikit-performance/
If you only wanna change frame, position of buttons, labels, ... you can call setNeedLayout or layoutIfNeeded
You will call setNeedDisplay when you are changing the property on which your view custom drawing depends. It will explicitly call drawRect: method forcefully.