How to set NSOutlineView to consider minimal content's widths with autolayout? - cocoa

I have NSSplitView with NScrollView inside it and view-based NSOutlineView inside NSScrollView, it has e.g. one column. My outline view must be scrollable vertically only and it must consider minimal width of column content to fit it. I think they must return -(NSSize)fittingSize with values {minColumnWidth, 0}, but it returns {0,0}. How can I do that?

Try to return the desired view size in (NSSize)intrinsicContentSize. I am not sure if I totally understand your scenario. You could add a screenshot or wireframe to make it easier to understand the setup. Whatsoever, take a look at my question dealing with a similar problem.
Maybe also check out the WWDC Session 232 - Auto Layout by Example. It covers a new split view API together with Autolayout (starting around 41:00 minutes).

Related

How can I position views over a NSTextView such that they have no fixed position, but a sort of gravity to a point?

So I have an NSTextView with text in it. Some of the parts of the text have a NSTextAttachment.Key so I can find their position in the NSTextContainer. I'm adding notes/annotations to the text right now just by hard coding the frame of the annotation to be under the given part of the text. This fails miserably when two annotations are close to each other(they then overlap), or when an annotation's text position is near an edge of the NSTextView(it then gets clipped and cut off).
What I would really like is to set a rule like, this view(the annotation), likes to be close to this given point, but is flexible. This view does not want to overlap other views or go beyond the bounds of the parent view.
The other rule which may be harder is, this view does not want to cover the NSTextView text. Since that text is not a view itself, one solution may be, since I'll know the font size, and the line height, I could calculate that if say the lines of text are at Y positions 100, 200, 300, etc. Then the annotation could only have Y positions of 75, 125, 175, 225, etc.
Some other notes:
This NSTextView is not editable. It is display only and updates based on changes to another NSTextView, so these positions won't need to be dynamic such that a user is adding text in realtime, rather at fixed intervals the editable textview's content is read, the annotations queried from the backend, and then the text is written into the read-only textview's NSTextStorage, and the annotation NSViews are added to the read-only NSTextView.
MacOS/AppKit only. No UIKit
Here is a diagram of the sort of thing I'm aiming to achieve, and was wondering what is the right tool in the AppKit toolbox to try and achieve this? Can something like AutoLayout work with these types of flexible constraints? Or is my only option to rollout something custom that does all of these calculations, and then gives a fixed NSRect to each annotation's NSView?
You can't do it out of the box but there are couple of things you could look into.
Exclusion paths will help you with not covering the actual text view. Whenever you create the note view, just add an exclusion path which could perhaps cover the whole line (meaning a rect of 0, y, fullContainerWidth, lineHeight).
Using NSPopover instead of normal NSViews. They can pop out of the actual window and won't be clipped outside the screen. There is no way to avoid overlapping with them, though.
There are some popover subclasses (such as SFBPopovers) which allow more flexible positioning.
In either case, you will need to do some maths to avoid overlapping. The best way to do this in your case is probably to enumerate the attributes/text attachments. From there, you can figure out which lines will need to have notes displayed, and calculate in advance how much they will take space, and if you'll have to display them both below and above the line.
Note that you will need to do this as you go along, because the layout and
attribute range rects will change as you add exclusions.
If you decide to go with NSViews, you might want to look into creating a specific container NSView subclass for displaying the notes for a single line. It's much easier to handle positioning the notes in local coordinate space, and to figure out how much space they take. You can then display this specific view on top of your NSTextView where needed.

Can NSCollectionViewCompositionalLayout support "growing cells"

I have a collection view showing a simple one-column list with a NSCollectionViewCompositionalLayout. The cells take the full width and have a fixed height.
I would like that, upon an external event, one of the cell grows in height (animated).
That could be for example :
when the cell is selected
when an image shown in the cell is downloaded
I found no way to do this in Apple's doc, when I think this is a fairly common use case. It seems that NSCollectionViewCompositionalLayout is very flexible in positioning cells, but very static. All cell sizes are computed once and for all.
Is there any API for this ? What's the way ?

What could prevent an NSView.layer to renderInContext:?

I've been working hard, searching the internet on that problem for 3 days and I'm now running out of ressource.
Currently porting an iOS app to MacOS (deployment 10.11). The problem:
I have a view hierarchy as below:
NSScrollview
documentView
grouping view
tiling view one
array of NSImageView (each one being a tile)
tiling view two
array of NSImageView (each one being a tile)
The two tiling views are overlaying completely, depending of UI one may be hidden or the second one has opacity set below 1.0 to blend the two tiled view.
Because of opacity requirement, as well as performance, views are CAlayer backed. This is done from IB where the to NSScrollview is checked for Core Animation. Thereoff, all the view tree is (implicitly) layer backed.
Works as expected, scroll, magnify, etc..
Then I need to make an image out of the document view to generate an SCNMaterial content (3D view).
On iOS the documentView renderInContext works as expected, and allows an image to be created.
On Appkit the context stay transparent, so is the image, a valid object while as if clearColor.
If the documentView.canDrawSubviewsIntoLayer is set at creation, the view tree renders OK. This can't be the solution since it prevents opacity setting to work.
Even when one tiling view is hidden (no opacity compositing) rendering fails.
I read that some kinds of views are not rendered. I don't use them. There are no filters, no masks, beside a default masksToBounds setting on all the view tree. I don't know why and where it is set. I tried to unset it on all the views at creation with no success. It is set again somehow, on the grouping view below the documentView. This may be the problem but why this property is out of my control ?
Alternative way to get view tree rendering, bitmapImageRepForCachingDisplayInRect: / cacheDisplayInRect:toBitmapImageRep: works the same : ok with canDrawSubviewsIntoLayer, KO otherwise. Apple code examples to make a texture out of a view are using either one of the two methods.
There are plenty of posts, mainly on SO, complaining about CALayer renderInContext and code to custom render a layer tree. Nevertheless, most are quite old and now there must be a simple standard way to achieve it.
Edit: among other attempts, I tried to set each view wantsLayer, with no success.
Well, as often when you post a request for help, you finally find the answer by yourself… Here it is:
Given the view tree as listed in the question, I achieved to render it by setting canDrawSubviewsIntoLayer on each tiling view. This way, the opacity compositing between layers is working, AND the views are rendered.
I post this as an answer, because it solves the problem.
As of WHY this works, here is my guess, but this is not a authorised answer: Each NSImageView tile, subviews of tiling view, have their origin set to their frame. This is not a transform on the layer but a position of the frame in the coordinates of the tiling view. This is a difference with the iOS code version where the tiles are positioned by a transform. I'm going to test further, and see if using a transform rather that a frame origin makes a difference to renderInContext.
Edit: after more testing it appears that the iOS version has a transform AND an offset to the tile.
So the only clue is that the layer system get lost when rendering in context on OSX when some subview have an offset ??
Summary:
The key point to the solution is to find the right layer where to set canDrawSubviewsIntoLayer

Unable to get dynamic table cell size working in XCode 6 iOS 8

I'm trying to adopt the adaptive layout in a new app and have learned quite a bit. For the last portion I had to dump text into a table and have the cells adjust to stay adaptive, seemed easy enough.
I read through a few tutorials and for iOS 8 it looks like it just comes down to two things:
Having estimatedRowHeight and rowHeight = UITableViewAutomaticDimension set
Having constraints set up right to create pressure on the cell itself
Shamefully my entire day has gone out the window trying to master those mere two points... I downloaded code provided from Keith Harrison on self sizing table view cells to see it work. I duplicated his cell into my larger project and it worked, however none of my own cells worked. I deconstructed everything in his project and minimized it to the point where little is left then tried making a similar cell from scratch. I've gone through and verified every constraint, every hugging/resistance setting, etc, and yet mine fail to expand the cell height.
If anyone can point out what I'm doing wrong (and it must be tiny because everything I see is the same) I have uploaded a minimized version of his example here (GitHub).
With this example I tried a cell with a single multiline label with constraints all around along with a cell as close as possible to his cell. I found that in many of my attempts everything looked identical however I would get a UIView-Encapsulated-Layout-Height constraint issue. With my last attempt I reduced the priority of the vertical spacing to the content container to 999 from 1000.
Things I have checked or tried with no effect:
Contraints are to superview (content container, not cell)
Label is set to 0 lines
Hugging and Resistance priorities the same as working cells
Reloading table once loaded
I have my solution working now after another long stab at it. Two things:
The UITableViewCells, while identical in every way in the storyboard had a rect tag within the storyboard source with a defined width and height. I looked everywhere for the values in IB with no luck. Taking that out fixed my problem for the GitHub test project I posted.
After moving over to the project I was initially working on the cells still were not resizing, but would when orientation was changed. I had to add a cellForRowAtIndexPath method to call setNeedsDisplay and layoutIfNeeded on the cell being requested.
Following the above everything appears to be working.

Automatic NSView resizing

I'm doing something with cocoa which I think is a bit complicate for a beginner like me. I tried a few things, but I admit I need some theory first, because I would like to understand exactly the meaning of this concepts.
I see that every NSView and every class that subclasses it has one thing called frame, and one called bounds. They both have a size with width and height and an origin.
I have an NSView with an NSTableView inside of it.
I have the size of a row from the table view, and I would like to set the height of both NSView and NSTableView equal to rows*rowSize, in a way that the group NSView+subviews is automatically resized when an object is added or removed to and from the data source of the Table View.
I made some experiments, but I did end a bit confused about frame, bounds, sizes and so on. I don't know what I should change and how.
Can you please give me an hint about what bounds and frame basically are, and how can I achieve that magic resizing?
Thank you for your replies in advance. Best regards,
—Albé
The difference between frame and bounds is covered very nicely in the View Programming Guide (under View Geometry).
You'll also want to peruse the NSView Class Reference, where you'll find some handy notifications, such as NSViewFrameDidChangeNotification and handy methods such as setPostsFrameChangedNotifications:.

Resources