Re: needsDisplay and subviews
Re: needsDisplay and subviews
- Subject: Re: needsDisplay and subviews
- From: Jeremy Hughes <email@hidden>
- Date: Thu, 09 Mar 2017 10:24:55 +0000
> On 9 Mar 2017, at 01:49, Quincey Morris <email@hidden> wrote:
>
> So, the correct answer to your original question, I think, is that if your model data has changed in such a way that the representation in custom views no longer reflects the data, then you should set “needsDisplay” on *every* custom subview that uses “draw(_:)”.
>
> If you just need your changed view to be re-composited with the same subview contents as previously, then you don’t need to set “needsDisplay” on the subviews, just the parent view.
OK - that disagrees with Ben’s conclusion:
"Thus, it seems to follow that so long a custom view's display() calls super, then all of its subviews should also be drawn when its needsDisplay is true.”
But maybe it is covered by the “as necessary” clause in Apple’s documentation:
display(): "Displays the view and all its subviews if possible, invoking each of the NSView methods lockFocus(), draw(_:), and unlockFocus() as necessary.”
I have a custom view that has two custom subviews, and is a subclass of a more general custom view. The code that tells the general (superclass) view that it needs to be redrawn shouldn’t have to know which kind of (subclass) view it is dealing with. So it would be necessary for the subclass view to override needsDisplay with an observer that sets needDisplay to be true for its subviews:
override var needsDisplay: Bool
{
didSet
{
for view in subviews
{
view.needsDisplay = needsDisplay
}
}
}
Currently, I don’t actually need to do this because I’m not trying to use layer-backed views (that happened accidentally through a bug or unexpected behaviour in Interface Builder), but the fact that Apple is unclear about how needsDisplay affects subviews means that I probably should do this in case they introduce new drawing optimisations in future versions of macOS.
The other puzzle in all this is why it should be the case that setting needsDisplay to be true on a layer-backed view actually doesn’t set it to be true:
> One other strange behaviour with the problem xib occurred when I added some debugging code to try and find out why the subview wasn’t being redrawn:
>
> view.needsDisplay = true
> print("view.needsDisplay: \(view.needsDisplay)”)
>
> and this consistently printed “ view.needsDisplay: false” after view.needsDisplay had been set to true. Despite this, “draw” (= drawRect in ObjC) was being called for “view” - but not for view’s subviews.
Before I discovered that IB had changed one of my views to be layer-backed, I tried using the didSet observer to pass on needsDisplay to subviews and found that it was setting the value to be false for subviews when I had set it to be true for the superview (that’s why I added the debugging code above).
So it seems that for layer-backed views, setting needsDisplay does cause the view to be redrawn - but the value is never actually set. If I needed to work with layer-backed views, it might be possible to get around this by overriding willSet instead of didSet.
I think NSView needs a “Redraws subviews” property (similar to “Autoresizes subviews”) that will take away the guesswork and hackery that we currently need to use in order to get some kind of consistent behaviour.
Jeremy
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden