Seeking a simple Mac OS NSTextView example using AutoLayout - cocoa

After much reading and experimenting, I still cannot get a simple TextView to resize fully in the horizontal direction using Xcode 5.0.2 in Mavericks. It resizes partially as the window is resized, then stops with long lines wrapped around even though my containing NSScrollView continues to resize as expected (it has four default constraints and no horizontal scroller).
Can anyone point me to a simple code/IB+AutoLayout example, preferably just a window containing just an NSTextView dragged in from the IB template library --- one that works? The Apple TextEdit sample code is almost irrelevant for this purpose although it does resize horizontally quite well. Also, there is the clip view for which I can find little information.
Any other tips appreciated.
Thanks.

Answering my own question:
Turns out that my problem had nothing to do with AutoLayout and little to do with NSTextView. It was the textfile I was using to test my code! This file was composed of records with tab-delimited fields.
Turns out that NSTextView comes with a default NSParagraphStyle with predefined tab stops that end at character 56 whereas my test file had tabs beyond that. Therefore, my lines wrapped around at the last defined tab no matter how much I stretched the window.
After changing my search terms, I found what I needed at the following links:
Premature line wrapping in NSTextView when tabs are used
How to have unlimited tab stops in a NSTextView with disabled text wrap
Apologies for wasting bandwidth.

Not sure why such a simple thing does not work in your case, but nevertheless here's what I did in Xcode to get an NSTextView follow window resize:
Create a new project (not document based in my case but it doesn't really make a difference)
Drag a NSTextView from the palette to your window. Align all four edges with the window edges.
Open the "Add constraints" pop-up (second button from the segmented control on the bottom-right part of your IB view.
Each of the four spacing constraints should show a number equal to the distance of your text view from the container window. If you aligned them, this number should be either 0 or -1. Click the down arrow for each of them and select "Use Current Canvas Value". Do it for all four. Make sure no other constraints are selected.
Click on "Add constraints" on the bottom of the panel.
Run your project. Your textview should resize with the window.
Also, as Jay's comment mentions, make sure you do not have any "leftover" constraints in your view. You can check this either by observing Xcode's warnings, or manually by inspecting your view's constraints by going to the Size Inspector tab (4th tab on the Utilities bar).
If you need to have your textview arranged in a more complex layout, it might be worth taking a look at the AutoLayout Guide.

Related

Why doesn't my NSWindow resize when I change auto layout constraints?

I think I have arrived at a decent understanding of how auto layout works in Interface Builder (ha). I've got a .xib that says "No auto layout issues". Here's two screenshots of it, with nothing selected and with things selected so you can get a sense of the constraints at work:
Now I would like to, e.g., decrease the vertical spacing between the "Total thumbnail size:" label and the "Use TIFF" radio button matrix. So I click on things to get that constraint selected, and I edit the "Constant" value of it to change it from 47 to, say, 30. When I do so, I expect that the window will shrink vertically by 17, so that all constraints continue to be obeyed. Instead, it shifts the vertical position of the "Size & format" label, breaking its vertical constraints in so doing, and then complains about "Content priority ambiguities" involving a bunch of items; here are screenshots of that state, showing the priority ambiguities:
It wants me to change vertical compression resistance priorities and/or vertical hugging priorities to allow it to compress/expand something away from its intrinsic size; but I don't want to do that. I want all of those items to retain their intrinsic size, and I want the window to resize. I can resize the window manually, by -17, and move the various items into their proper positions, and then it says "No auto layout issues" again; so there is really nothing difficult or ambiguous about this situation except that for some reason it refuses to resize the window as it ought to. So, my question is: how do I avoid it doing this, and have it just resize the window and move things properly on its own? I don't understand why it's so confused; it seems to me that there is a clear, unambiguous chain of vertical constraints from the top to the bottom of the window, and changing one of those constraints ought to simply force the window to resize. I've tried using "Update Frames" but it doesn't seem to help.
I think I have uploaded the .xib file, prior to the constraint change, to my Dropbox here: https://www.dropbox.com/s/vp90s1fh692i8pi/CopyThumbs.xib.
I grabbed your xib and played around with a few things... I can only find two items that would be causing problems.
But first, a couple tips (based on my experiences):
Start by making your window larger than you'll need
with your layout, make it maybe 600 x 600
As you add UI elements add only Vertical and Leading constraints (we can center the Cancel/Copy buttons later
of course, I also mean Horizontal inter-element constraints
For wrapping multi-line labels (i.e. your "Choose how you want..." label), give it a specific Width constraint
285 is a good value for your layout... you can adjust this later as desired
Don't give a Bottom constraint yet
Your xib now looks like this (I left your Cancel button Leading as you had it >= 50):
Now you can tweak your vertical spacing constraints, without worrying about the window frame sizing.
Once you're happy with the layout, you only need one Trailing constraint (on your multi-line label) and one Bottom constraint (on the Cancel button).
Add those constraints, and your window frame should resize itself. If it doesn't, selecting "Update Frames" should fix it.
The two problem items that I mentioned... you have Content Hugging Priority on both "Matte thumbnails..." and "Frame thumbs..." set to 250. Those should both be at their default of 750.
Your Cancel/Copy buttons should horizontally center themselves, with your current constraints. I'd suggest, though, putting them in a StackView, and then constraining that StackView Top to the element above it, and Bottom to the Superview... and thenHorizontally Centered.
Edit
Note: I don't work for Apple... these comments are simply my anecdotal observations.
First, Interface Builder is (as we all know) not the same as run-time output. It's close, but it's certainly not identical.
Second, IB makes a lot of assumptions -- while at the same time, it has no idea what we're going to do next.
A perfect example from iOS development:
If, in IB, I add a UIScrollView to a view without adding any content to it, IB will endlessly complain about Content Size Ambiguity... and won't even position the view to reflect the constraints.
That's because IB doesn't know that I'm going to add subviews (with proper constraints) at run-time. And the only way to get rid of the Red "Error" messages is to add a subview in IB which I would then have to immediately remove at run-time (ugh).
IB also tends to complain / warn about "Fixed width constraints may cause clipping" and, as you're experiencing, "Localization Issue: Trailing constraint is missing."
It doesn't matter if my label is static (text will never change) or if I have the constraints set exactly how I want them. IB is going to try its darnedest to convince me that I need to change things.
This is one of the reasons many people move away from using Storyboards / XIBs. For my job, we don't use any XIBs, and the only Storyboard we use is for the LaunchScreen (iOS).
I might lay things out in IB to start, and to get a good idea of how I want my layout to look, but then I write it all in code for the end result.
Not that I'm saying this approach is better... plenty of times when I think to myself "Hey, I can drag/drop UI elements, add constraints and IBOutlet / IBAction connections, and I'd be done already!"
Again, though, just my personal thoughts on the topic.

Why does this simple autolayout collapse in IB?

I have a window with a textview in a scrollview and two buttons. I have added constraints at all sides, leading, trailing, top, and bottom. For the buttons I have fixed width and height, and distance to bottom and edge.
I want it to look something like this:
And this is what Interface Builder keeps giving me:
It also keeps offering to fix ambiguities by adding missing constraints, but actually clicking the button has no effect. No constraints are added. The error (and the offer to fix it) remains.
I've tried added the constraints it is asking for, although I can't see why they would be needed and at least the buttons already have (fixed) width constraints. But I keep getting errors and the window keeps getting shrunk to nothing.
When actually running the program, the window looks fine. But I suspect these autolayout errors have something to do with this problem: NSTextView in magnified NSScrollView breaks on resize
The project is here: https://github.com/angstsmurf/spatterlight/tree/helpviewtest
(The branch helpviewtest is a cut down test case created specifically for this problem.)
You have a Text view embedded in a Clip view embedded in a Scroll view, none of which have an intrinsic content size.
IB has no idea what's going to go on at run-time.
So, while everything looks great when you run this, your code will have supplied enough information to lay things out as desired.
To get it to "look right" in IB (and avoid the errors/warnings), you can give the ScrollView a Placeholder Intrinsic Content Size:

UITabBarItem grows when touched

I have a tab view controller with 3 tabs, custom icons. I used insets to enlarge them slightly and compensate for the lack of titles. All of this is done in the story board, the only code for these items is setting the text to "" since it always wanted to pick up the View title no matter what I set in the story board.
It look like this:
now, if I repeatedly tap a tab bar item, this happens:
It happens to all three, and it will keep growing if you keep tapping. I'm not setting the size, these are image sets and all I did was change the insets in IB
Any idea what's happening here? (Xcode 6.4 iOS 8.4.1)
I finally found an similar question here :
iOS Tab Bar icons keep getting larger
it seems that any inset that makes the image larger will be applied every time you touch it. It doesn't really make sense but if I use insets to only center the image and not enlarge it the issue goes away

Auto-layout issue with UIButton with long title that compresses an aligned Segmented control which should have fixed width and should never compress

In my Xcode 6.2 Swift project I have an issue with Auto-layout (I'm also using size classes) that I'm not able to figure out...
In Main.storyboard I have a view containing, among the others interface elements, a UIButton and a UISegmentedControl that are positioned at the same height on the opposite side of the view.
I'm setting manually all the constraints in Interface Builder (none in code) and my every view is working just fine, except in this case (and this particular issue only occurs when I have a long text).
The button is aligned to the left border of the view and its constraints are:
Leading space to superview == 0
Trailing space to segmented controller >= 8
Top and bottom space to other interface elements == 8
The segmented controller (which has 2 segments) is aligned to the right border of the view and its constraints are:
Trailing space to superview == 0
Leading space to button >= 8
Top and bottom space to other interface elements == 8
The button in the storyboard has a title "Some title", but actually the actual title is always set in code in ViewWillAppear:
myButton.setTitle(aStringThatSometimesIsPrettyLong, forState: .Normal)
The visual result I need to achieve (on every possibile device and orientation) is that the Button title I set in code, while it can be displayed in good length in the interface, should never compromise the size of the segmented control, compressing the labels of the two segments.
So, I want the size of the segmented control to be fixed and I'm willing to accept the fact that the Button title, if long, can be truncated with dots.
Instead, no matter what I try (and I'll explain what I've tried in a moment) when the Button title is very long it is not truncated, instead the segmented control is compressed and therefore its two segments labels are truncated.
So far, I've tried, separately and together, these steps:
Adding a width minimum constraint to the segmented control.
Incremented (in steps, up to 1000) the Content compression resistance of the segmented control while decreasing the correspondent value of the button.
Increased (up to 1000) the Content hugging priority of the button.
I think I can't set a maximum width to the Button, because it can stretch depending on the title set in code and, more important, on what device the app is run on.
My biggest issue is that, no matter what I try, when I run the app I always get the same behavior (button title completely shown, un-truncated, and compressed segmented control). It seems like adding these constraints doesn't change anything, and it never happened to me before with Auto-layout... messing up, a lot, but no change adding constraints, this is new!
Maybe the issue is that the button title is set in ViewWillAppear and not in the Storyboard, but my app wouldn't work properly if I couldn't set its title in code.
Last, but pretty important, I have to admit that, while I've managed so far to get Auto-layout and Size classes working on all devices and orientations for all the (over 10) viewcontrollers of my app, I've actually never written a single line of code for Auto.layout and Size classes: I've done everything in Interface Builder and, if possible, I'd really love to continue this way.
Any suggestion would be really, really appreciated!
Thanks in advance,
Cesare
As #KenThomases pointed out, the constraints I was setting were actually right (actually, it also works with less constraints now that, thanks to his answer, I figured out the issue), but the Segmented control wasn't getting its intrinsicContentSize. Fixed that, now everything's fine.

Subview that expands with window using NSAutolayout

I'm trying to learn auto layout so I can set up a moderately complicated display the way I want. I'm starting with a simple version. At least I thought it was simple.
I have a content view containing a NSScrollView, and a zoom slider. The scroll view is, of course, just a window into a larger 'canvas' on which the user can do things.
I'd like the scroll view to be as big as the window allows, with the slider underneath.
I've tried many things none of which work, in some cases when I resize the window smaller, the scroll view goes on up over the window's top bar, obscuring the title and the red yellow, green, dots.. this is just a grumble, I won't attempt to describe how I got it.
I'm working with Visual Format Language.
The immediate problem: I can only get the thing to work at all if I put in a hard size constraint on the scroll view.
I've got constraints like #"V:|[ScrollView]-[ZoomSlider(==35)]-| and
#"|-20#1000-[ScrollView]-|"
With these, nothing shows at all, until I put a hard size on the scroll view:
For example, #"V:[ScrollView(>=70#20)]" and #"[ScrollView(>=140#20)]" results in a little tiny scroll view (as expected) just above the slider.
Window is resizable, all right.
Is there a simple way to make the scroll view resize to occupy the most space possible when I resize the window? The only way I can think of off hand is to produce metrics for the scroll view based on window size, and use a notification to change the constraints when the window size changes. There should be something simpler!
THanks.ee
OOps. Thought I knew the answer until I started to write it.
AT least here is a partial explanation of things that were causing me problems.
You can't add constraints that position or size the Window's content view. But apparently you can mess them up by deleting them programatically. Some of my problems were solved by getting rid of
[self.myContentView setTranslatesAutoresizingMaskIntoConstraints:NO];
and
[self.myContentView removeConstraints:self.myContentView.constraints];
This left me with a lot of conflicting constraints. I fixed this be eliminating all content window constraints that I could in IB, then by marking the rest as placeholders.
I've got a ways to go before I understand how to use auto layout, but doing it in code is easier (for me) than doing it with IB

Resources