NSScrollView incorrect content size - objective-c

I have an NSScrollView that is the parent of a custom NSView subclass. The subclass uses the NSScrollView's contentSize method in order to layout its subviews.
The issue is that upon first launch, NSScrollView reports the contentSize wrong. It reports the size as being 15px more than it should be (the width of the scroller). So it seems to me that it is returning the contentSize without taking into account the scroller width; however, as soon as I adjust the frame of the scroll view (by resizing, etc.) the content size is reported properly. It seems to be just a problem upon initial launch.
Should this be reported as a bug, and are there any good solutions to this? I could use the dirty way of performing a check during layout to see if its the first time the method has been called, and then deduct 15px from the content size, but if there's something better, that would be appreciated.

I just came across a similar problem and the way I solved it was to observe the notification NSViewFrameDidChangeNotification on the Scroll view's content view (in your case the custom NSView).
This notification gets triggered when a scrollbar is added/removed from the scroll view, at which point you can reposition your view's content.

When are you checking the content size? Is it happening as your view is being instantiated from the nib file, or after the nib has been fully unarchived?
What I would probably do is invoke your layout method from -viewDidMoveToWindow: or -awakeFromNib

Are you using the option to hide/show automatically the scrollbars?

Related

NSScrollView documentView cannot be scrolled

Coming from an iOS background, I presumed that NSScrollView would work out of the box, and I presumed that contentSize would reflect the size of the documentView passed to it. This is not the case, if the NSScrollView is created programmatically.
First issue was: why does contentSize not update when a document view is passed in.
Second issue was: why can I not scroll the scroll view, despite the fact there was more content.
The answer to the first question appears to be: don't look at contentSize, look instead at [[scrollView contentView] documentRect].
The answer to the second is that you have to explicitly set hasVerticalScroller and/or hasHorizontalScroller. The scroll view will then dynamically create NSScroller views.
You can also use setAutohidesScrollers:YES to make those appear only when necessary.

NSScrollView resize automatically

I have a NSScrollView, which I would like to resize automatically.
I would send a method to it's documentView to get the size of it, like in a table view I would calculate and return the required size of the rows.
My problem is, when?
How can I figure out if the documentView of the scroll view has been resized?
Has anyone an idea how to do this?
Which methods do I have to override?
I'll publish the project on Github if I figure it out.
Any NSView or a subclass will call -viewWillStartLiveResize and -viewDidEndLiveResize when resizing begins and ends.
NSView Class Reference
Or, if you're interested in knowing when the window is resized:
Stack Overflow: get window height/width in real-time

Is there a function to know the useableSize of a view?

It must take into account:
statusBar (which can be 40 points if you have hot spot)
TabBar
NavigationBar.
Basically at viewDidLoad I see that my view has a size of 320*480.
I wonder where did iOS decide that as the screen size of my screen. I use UIStoryBoard.
So, on viewDidLoad, I intended to resize that.
I am not even sure if this is the right approach.
Note: the issue I am facing doesn't seem to happen if I do not use storyBoard.
At viewDidLoad, when I use XIB, the content of self.view is correct, namely 416, instead of 480, due to UInavigationController and UITabBar
Try overriding the UIViewController viewWillLayoutSubviews method. The view's frame will be set by then.
In the viewWillLayoutSubviews method, the view controller's main view is the size you need to know. It has been adjusted for status bars and nav bars and tools bars and tab bars. It also takes into account orientation. There is no single method where you can ask what the size will be. Besides, there is no need to ask such a question. Create all the subviews you want in viewDidLoad. But lay them out based on the view's size in viewWillLayoutSubviews.

Xcode's auto layout is only effective in viewDidAppear and this is very problematic

After upgrading my project to iOS 6, I realized that auto layout is only effective in viewDidAppear and most of my code expects the view's frame to be available in viewDidLoad. This limitation renders the really nice auto layout feature almost useless for me. Is there any suggestions to help me use auto layout?
For example, sometimes the developer needs to adjust information about a subview based on where auto layout chooses to place that particular subview. The subview's final location cannot be ascertained by the developer until AFTER the user has already seen it. The user should not see these information adjustments but be presented the final results all at once.
More specifically: What if I want to change an image in a view based on where auto-layout places that view? I cannot query that location and then change the image without the user seeing that happen.
As a general rule, the views frame/bounds should never be relied on in viewDidLoad.
The viewDidLoad method only gets called once the view has been created either programmatically or via a .nib/.xib file. At this point, the view has not been setup, only loaded into memory.
You should always do your view layout in either viewWillAppear or viewDidAppear as these methods are called once the view has been prepared for presentation.
As a test, if you simply NSLog(#"frame: %#", NSStringFromCGRect(self.view.frame)); in both your viewDidLoad and viewWillAppear methods, you will see that only the latter method returns the actual view size in relation to any other elements wrapped around your view (such as UINavigationBar and UITabBar).
As told by #charshep in a comment, calling view.layoutIfNeeded() in viewWillAppear can do the trick.
Quote of his original comment
I had trouble getting a table view to appear at the correct scroll position when pushing it [...] because layout wasn't occurring until after viewWillAppear. That meant the scroll calculation was occurring before the correct size was set so the result was off. What worked for me was calling layoutIfNeeded followed by the code to set the scroll position in viewWillAppear.

Setting subview's width equal to window width on launch

I'm struggling getting a subview (which is acting as a custom toolbar [I need a NSView rather than an NSToolbar]) centred within an INAppStoreWindow..
The subview is being added correctly, and stretches correctly only if the window is exactly the same width as the custom view that I've created in IB.
If the window opens wider than the custom view, it does not stretch properly. The window seems to open in exactly the same state as I left it (in Lion), which therefore means I have to set the width of the custom view to the restored window width on launch.
It's also important that the buttons etc I have placed in the centre of the view in the nib remain centred...
How do I do this?
Edit: to make this clear, how do I get a restored window's width? I have set it to 480 in the nib file but if I resize the window, quit then restart the app, window.frame.size.width still returns 480, not the width I quit with..
Many thanks
I take it you are not creating the NSWindow in interface builder, you can override -[NSView viewDidMoveToWindow] or -[NSView viewWillMoveToWindow] to set the width, there are also viewDidMoveToView equivalents which may make more sense since you view gets added to the NSWindows contentView, there is also awakeFRomNib which you can override which may b he better choice if you only have to worry about the issue once when you vie loads from the Nib file.