This article from Setneedslayout this method, share with its related UIKit view interaction, use scene and so on content.
UIKit provides these methods for UIView to update and redraw the view:
Public func setneedslayout()
Public func layoutsubviews()
Public func layoutifneeded()
Public func setneedsdisplay()
Public func setneedsdisplayinrect(rect: cgrect)
Public func drawrect(rect: cgrect)
Run-time View interaction model
Whether the user interaction is triggered or the code is triggered automatically, the sequence of events presented is equally applicable, and the Setneedslayout method is used here:
UIKit interactions with your view objects
The corresponding sequence of events is as follows:
User Touch screen
Hardware report Touch event to UIKit frame
The UIKIT framework packages touch events into uievent objects and then distribute them to the appropriate views
The event-handling code responds to the corresponding event, and the code can be:
-Change the frame, bounds, alpha and other properties
-Call the Setneedslayout method to mark the view (or its child view) as requiring layout updates
-Call Setneedsdisplay or Setneedsdisplayinrect: method to mark the view (or its sub-view) to be redrawn
-Notify Controller of data changes
If the geometry of a view changes, UIKit updates its child view
If any part of any view is marked for redrawing, UIKit will ask the view to repaint itself
Any view that has been updated is combined with the rest of the app's visual content and is sent to the graphics hardware to display
Graphics hardware transforms interpreted content onto the screen
Method invocation Logic
In the process above, we can touch the method mentioned at the beginning of the article, and their invocation logic is this:
Setneedslayout will give the current UIView a flag to indicate that subsequent calls should be made to the Layoutsubviews method to adjust the layout of the current view and its child views.
Setneedsdisplayinrect: A flag is given to the current UIView to indicate that subsequent calls should be made to the DrawRect: method to redraw the view.
View Drawing Cycle
Apple's official documentation has made it clear that developers should not call Layoutsubviews and drawrect directly, but should override these methods in subclasses when you think the system default layout and redraw do not give you the desired effect, and then separate through Setneedslayout and Setneedsdisplayinrect: to make the call.
Of course you can set setneedslayout for multiple UIView, and when the next view Drawing Cycle arrives, multiple UIView views will change the layout together.
So what is this View Drawing Cycle exactly, and the official explanation is this:
The system waits until the end of the current run loop before initiating any drawing operations. This delay gives you a chance to invalidate multiple views, add or remove views from your hierarchy, hide views, resize VI EWS, and reposition views all at once. All of the changes reflected at the same time.
Obviously it's more efficient to use Runloop to aggregate multiple changes together in one Cycle for rendering.
(My personal understanding of view Drawing Cycle is this: UIKit need to handle very many events, which combine to become a very complex sequence of events, where certain points are UIKit specifically provided to UIView for view changes.) As mentioned above, we have the opportunity to make various view changes before the end of the current run loop, and these changes will be reflected in the next run loop, so view Drawing Cycle is what we get through UIKit in the run loop UIView Re-layout, redraw the cycle of opportunities. Where there is no understanding, please comment. )
How to use the View Drawing Cycle
A very common example is that an IPad App, with a horizontal and vertical screen with different interface layouts, you can monitor the device rotation, execute the Setneedslayout method when the device is rotated, and then layoutsubviews In the inside by judging the next is the horizontal screen or vertical screen to make different layout settings. Basically you can't just make a single UIView layout change in this method, but a lot of changes, then the APP will execute the changes when the next View Drawing Cycle arrives, which is the most normal situation.
So what if I don't follow Apple's rules and call Layoutsubviews directly? We can guess: because this method provides the layout we need, so UIView will be laid out in the way we want it, but it's less efficient because the timing of requests for various view modifications is fragmented. So the important thing is to know when the layoutsubviews will be triggered:
Init initialization does not trigger Layoutsubviews
Addsubview will trigger layoutsubviews.
Setting the frame of the view will trigger Layoutsubviews, of course, if the frame value has changed before and after the setting
Scrolling a uiscrollview will trigger layoutsubviews
Rotating screen triggers the Layoutsubviews event on the parent UIView
Changing the size of a UIView also triggers the Layoutsubviews event on the parent UIView
Then just do it the way Apple wants it (via Setneedslayout and setneedsdisplayinrect: Call Layoutsubviews and DrawRect:)
But some things are more special: you open the IOS clock app, to see the stopwatch page inside, the page two buttons are not UIButton default animation, click, the button will change its status (color, internal Label content), this situation we need to jump out of View Drawing Cycle, to achieve an instantaneous change in the effect. The implementation method is as follows:
Extension UIButton {
func quickbuttonaction() {
UIView. Performwithoutanimation({
//Do something
self. layoutifneeded()
})
}
}
It can be seen that layoutifneeded as an auxiliary option gives Setneedslayout a feature that can be executed instantaneously. Of course, this "option" is off by default.
Setneedsdisplay Supplement
Setneedslayout's use of the scene has been mentioned before (IPad App), here is a chestnut to say Setneedsdisplayinrect: The use of the scene.
If I need to draw a line between two points, there are two dotview, I need to draw a lineview. I have implemented the concrete drawing method of Lineview (based on two points) in the DrawRect: method. So if I want this line to always change according to two points, it needs to be executed when the Dotview position changes:
Lineview. Setneedsdisplay() //Redraw Lineview
As for DrawRect: When will the method be triggered:
From StackOverflow
A good reference link: What is the relationship between UIView ' s setneedslayout, layoutifneeded and layoutsubviews?
From Setneedslayout.