I am on Xcode 8.2, Objective C, Mac OSX, not iOS.
I have a view shown in a popover like this:
Once i select an option in the second NSPopupButton, the blue text gets replaced with another LONGER text (5 lines instead of 3) - Unfortunately the view doesn't grow to reflect the changes!
Only if i close the NSPopover and reopen it, the view is correct:
The view is completely built with autolayout and constraints. There's NO constraint limiting HEIGHT or WIDTH for any subview, just setting distances to superview. So my quesiton is, how can i update the view after a selection in the NSPopupButton. I already tried (in the viewController)
[self.view setNeedsLayout:YES];
But it seems not to work. I checked these posts but they did not help me with my issue:
Resize current view using NSLayoutConstraints
Edit:
The new text (on NSPopupButton selection) is set like this:
[self.descriptionTextField setStringValue:self.currentSequenceItem.descriptionText];
I found the solution and i'd like to share it.
Once you've set all your constraints make sure to call
[yourTextField setPreferredMaxLayoutWidth:100.0f]; // Whatever you need
Otherwise the textField will tend to scale horizontally making all your text a one liner.
If that property is set, it'll scale vertically and will update all constraints as excpected.
Related
For a MacOS app, I have a Window, containing an NSView; into that view, I want to add a subview with a constant size and height.
When loading the subview programmatically by [myView addSubview:mySubview], I want the NSView *myView that is hosting the subview to change in size so it accomodates the subview, and the window to change in size accordingly; so that the edges of the NSView inside that Window keep the same distance to their surroundings in the Window as before. How do I achieve that most efficiently and which properties do I have to specify in IB to make that work? Do I have to adjust the size of myView and of the Window programmatically by hand or can I achieve this in a more beautiful way?
There are multiple ways to achieve this.
A simple one is to set autoresizingMask the value(s) you want.
The mask you can see in Interface Builder are represented by predefined numbers (NSAutoresizingMaskOptions) that you will combine with bit operation
view.autoresizingMask = NSViewMaxXMargin | NSViewMaxYMargin;
which is simmilar to Autoresizing like in this screenshot of IB
The checkmark on Layout Translates Mask Into Constraints has to be made, either in IB or programmatically so they are used as constraints.
view.translatesAutoresizingMaskIntoConstraints = YES;
The relative positioning to its enclosing superview is defined when the view is instanced with -initWithFrame: with the given frame or with the values set in IB when it creates an instance and inits the UI element via -initWithCoder: .
Be aware this does not stop the autolayout mechanism of IB to warn you that your desired coordinates, sizes and constraints are maybe clashing with constraints.
As suggested by #Willeke, I needed to understand and apply Autolayout. To make it work in IB, I set the autoresizingMask of my subview to stick to all for sides and automatically adjust width and height. Even though it can be done completely in IB, I think programmatically this would be
subview.autoresizingMask = NSViewWidthSizable | NSViewHeightSizeable;
As pointed out by #Ol Sen in his answer, Translates Mask Into Constraints also has to be activated.
To arrange the elements inside that subview that is added programmatically as described in the opening post, I rely on nested stackviews and resize them instead of resizing the parent.
The only problem left is to correctly adjust the frame of the subview to match the parent view before adding it. If this step is left out, the contraints the autoresizing mask of the subview is translated into when adding it will result in the correct resizing behaviour, but wrong margins. The essential code looks like this:
MySubViewController *subViewController = [[MySubViewController alloc] init];
subViewController.view.frame = superView.bounds; // Correct the margins
[superView addSubview:subViewController.view];
I have made a custom UITableViewCell called "SwitchCell" that has a switch.
In iOS9 Only, using Xcode 7 beta, the Content view in the cell is on top of the switch. (See screenshot of View Hierarchy. You can clearly see that the content view of the cell is on top of the other views. ):
So all the touches to the UISwitch are intercepted, and the IBAction does not fire.
In iOS8, this is not a problem. See screenshot for iOS 8.4 simulator. You can see that there is no content view on top of the controls:
Has anyone had this problem?
I tried remaking the NIB from scratch, but the same result occurs.
My NIB is a freeform size view with No status bar. It has two outlets: one for UILabel, one for UISwitch.
EDIT: please make sure to check the answer below that asks to verify that the cell's root view is not just a UIView but a UITableViewCell. This issue may also be a side effect of this.
After more investigation and searching, i found my solution here:
Button in UITableViewCell not responding under ios 7
What fixed it for me was:
cell.contentView.userInteractionEnabled = NO;
This prevents the cell content view from taking over the touch events, even though it's on top of the other views.
This issue was not only happening on iOS9, but on iOS7 as well. In iOS8, the Content view was behind the controls.
Problem can be in .xib file for your cell. When you create cell in separate .xib, be sure to drag UITableViewCell on canvas, not UIView.
SWIFT
I had an issue where my buttons in my custom tableviewcell swift files were working just fine, but then I upgraded to Xcode 12 and then all of a sudden I couldn't access them anymore (meaning my taps were not being recognized). The cell content view seemed to be interfering in the hierarchy and this like saved me:
cell.contentView.isUserInteractionEnabled = false
I put the line in cellForRowAt.
Thank you to #FranticRock
I had this problem when I was reusing a cell as a .xib. I didn't realise but when I first created the xib the default view that it created was in fact a UIView and not a UITableViewCell. It seems that at some stage UIKit adds the content view on top of my other elements and therefore interrupts certain events (e.g. touch events).
I resolved this by opening my xib file and dragging a UITableViewCell onto the canvas and copying my UI elements from the old view to the new cell.
Afterwards, additional settings also became available in the attributes inspector that matched those for a UITableViewCell.
I've an NSTableView with several NSTableColumn objects that appear to have all the correct auto-resizing flags set. However, every time I rebuild the table's contents, the columns all return to a narrow size -- unless I click and manually resize the window.
The NSTableView is inside:
NSWindow
NSView
NSScrollView
NSTableView
(other NSTableView objects: NSTableColumn, NSTextFieldCell, NSScroller (x 2)
Column resizing mask is always:
NSTableColumnAutoresizingMask
NSTableColumnUserResizingMask
The table is created always set with:
[theNSTableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
After reloading the table with data,
[theNSTableView reloadData];
[theNSTableView tile];
...and even:
[theNSTableView setNeedsDisplay:YES];
All views are set to "autoresizesSubviews".
Neither the NSView nor the NSScrollView have any referencing outlets -- could that be the problem?
After discussing this issue at length with Apple Developer Technical Support, they believe there may be an issue with Carbon-Cocoa integration.
However, they also point out that I really should not set NSTableViewUniformColumnAutoresizingStyle and I should be calculating the widths of all my columns in my own code, and then either telling the column to remember its width, or storing the width and making sure to set the same width on each column AFTER I programmatically create the column.
While I can accept this, I had been at least hoping I could programmatically invoke the same method that is called when a user double-clicks on a column divider and the column resizes itself to fit all of its cell text contents. However, DTS tells me those functions are not available.
I have come across other solutions to this issue here on SO and I will see if they can be adapted to create an optimal solution.
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.
What I need may be pretty basic, but I'm definitely not sure as to how to proceed (I've done that before but none of my choices seem that Cocoa-friendly).
Ok, let's say we've got 2 NSViews - one next to the other:
The one on the left serves as a menu.
The one on the right will show a NSView (from a different XIB perhaps?) depending on the selection on the menu.
My questions :
How should I go about loading the different NSViews into the rightmost NSView?
How do I make sure that the subview (the one currently active) is properly resized when the window is resized?
rdelmar's solution should work, but another approach, which may be simpler, is to use an NSTabView to handle switching between the content views. You can hide NSTabView's tabs using the settings pane in interface builder, or by calling [self.tabView setTabViewType:NSNoTabsNoBorder]. I'd probably use a table view for the left side. When the user selects a row, you do something like:
-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
[self.tabView selectTabViewItemAtIndex:[self.menuTableView selectedRow]];
}
The NSTabView can/will take care of properly resizing its content views as long as you've set up its and its content views' autoresizing masks (springs and struts) properly.
You should be able to create a custom view in IB that looks like your yellow view, and set its resizing behavior to expand in both directions with window resizing. Then, when you get your new view (by just referencing one you already have or loading a new xib), add it as a subview of the custom view, and set its frame to that of the custom view. I think that views resize their subviews by default, so it should resize correctly with the custom view.