I am working on OS-X app, and I need advice on the window size.
Before someone to jump and declare this question as duplicate, I have read this post:Window Size for Mac application but it didn't help me to solve my issue.
My issue is the following. I use NSTableViews to display some of the data. However in some windows, I am getting horizontal scroll bar in the NSTableView due the numbers of the columns.
Things to be worse, the data in some of the columns are not completly visible, you have to resize the column to reveal the complete text in that cell / column.
I am thinking of increasing the initial window size, but I can't decide how much.
My current window size is 1024 x 768. User can make the app full screen, and window can be resized to be larger than this size, but not smaller.
Any help will be deeply appreciated.
Regards, John
For the table, you should set minimum widths for each column. Select each column in the document outline and view the Size inspector. You should also review the Resizing pop-up on the Attributes inspector.
Similarly, you should review the Column Sizing pop-up on the Attributes inspector for the table view itself.
With respect to the window size, I recommend that you use auto layout if you're not already. Apply appropriate constraints to all of the view, ultimately relating them (directly or indirectly) to the window's content view. Then, don't set a minimum size for the window itself. Let the constraints impose an effective minimum (and potentially even maximum) size.
The trick though, is that not all views will have an intrinsic minimum size. For example, the table view itself may not get any narrower than the sum of the minimum widths of its columns, but it's in a scroll view. The scroll view is allowed to get narrower than the table view, resulting in horizontal scrolling. So, you may need to add an explicit minimum width constraint to the scroll view.
If you set constraits for text inside the rows, you may get some horizontal scrolls. But if you set the constraits for the app elements like UITableView to the borders of the app window, you may resolve this issue.
Related
I am working on a project with multiple buttons on a viewcontroller and I used autolayout. I want all the buttons to have equal widths and heights and I have horizontal/vertical spacing like this:
The result on multiple devices is like this:
For the example I gave the buttons a background color, but in fact they will be filled with images of all kinds of sizes. I have image assets (#1x/#2x/#3x) for the buttons. For example, the #2x image assets will never be bigger then 100width and 75height (points).
Some of the button images can be changed by the user. So I want the button size to be ‘independent’ of the images inside. The buttons should NOT resize based on the image ‘inside’.
So I want to first(auto)layout the buttons, without the images ‘filling’ the buttons, so that the buttons will have the optimum size for the biggest sized images in my project (for the #2x image assets as mentioned:100width&75height points).
When I autolayout the buttons, and afterwards fill them with the images, xcode ‘wants’ to let me update the frames because of misplaced views. I do NOT want the images affecting the autolayout.
If I just run the app on the simulator or on a real iphone, it runs fine. But I have all these misplaced views warnings. What should I do? How will I 'tell' Xcode(7.1) that the images should NOT affect the width and heights of the buttons?
I have the feeling I have a slightly wrong approach to this (auto)layout problem, but I can not yet put my finger on it. I think I make some kind of logical error.
Is it good practice to first (auto)layout the buttons and then ‘fill’ with the images? Or should I fill the buttons with the images and then (auto)layout?
Here an example with images which are of equal widths and heights:
Regarding the earlier question about conflicting constraint:
So I want these buttons to have equal width and heights: ideally 100width and 75height in points. The width will be alright, but the heights is somewhat difficult when I am using autolayout for different sized viewcontrollers (with a scrollview on it). I want to use additional constraints that 'says'; the buttons should NOT have a height value lower then 75 points. If I use a fixed height constraint, with 'equal or higher then' 75 points I get a conflict with the equal heights constraints (off course). I guess I should work with priorities, but I tried, and I did NOT succeed yet with it.
How should I proceed?
Help is much appreciated!
Question 1:
Of course you're getting a conflict when setting two height constraints of which one computes to 1/3 of the screen width (≈ 107px excluding padding on the iPhone 4) and the other enforces a minimum height that is bigger than this value (e.g. 120px).
Fortunately there's a way out of this using priorities:
Set the fixed height constraint's priority to a value below the priority of your 'greater or equal' constraint. This way autolayout will choose the fixed height constraint only if its constant is greater or equal to the constant of your 'greater or equal' constraint. Otherwise the constant of your 'greater or equal' constraint will be used as the view's height. Makes sense, right? :)
Question 2:
You can achieve the desired behavior as described in your second question by enforcing a fixed height and width for your image view and setting its content mode to "Aspect Fit". In Interface Builder there's a drop down menu for that:
In your case the best way to give the image view fixed dimensions is to pin all four sides to its superview (because the superview has a well-defined size):
So when you apply these leading, trailing, top and bottom constraints to all your image views the images will automatically resized according to the constraints and the result will look like this:
I am trying to create the following layout with a NSTableView:
A big banner per section on the side and regular text content rows on the right side.
The Image on the left side is the problem. It should behave like a floating section when scrolling (stay below the section header). It seems impossible to have the view part of the NSTableView as each column of a row needs to have the same height.
I already tried a lot of things, but I need some input which is the right direction.
What I tried:
Add the image view as a floating view into the NSScrollView? That seems like a good approach, but it doesn't stick on top while scrolling and the (re)positioning within the table is... tricky. Any hints here?
Add the view into the section header and disable clipping somehow (to make them larger than the section)? Couldn't make that work.
Having a table with NSStackViews per row that host itself tables - that did work, but: Independent selections per table is not what I want.
Ok, I finally found a solution.
The view is added to the floating view container of the NSScrollView that holds the NSTableView. I use the bounds of the row views and translate that to coordinates of the floating view container.
I also modified the selection drawing to make it look good and recalculate the coordinates on animations.
I currently have a split view and when i resize the app window i want only the right subview to get larger (so left stays exactly the same size). I have a nstextfield in the right subview where i can type stuff in. However, in certain circumstances I call [_textFieldInQuestion setEditable: NO]. After doing so, when i try to resize the app, the right will get larger up till a certain point, then the left will grow. I saw a post on SO where I should subclass the nstextfield to achieve the behavior, but i was wondering if there were any alternatives that were more elegant and if not, how does one go about override the autolayout methods to produce the behavior i described.
When a text field is non-editable, it has an intrinsic width based on its content. (When it's editable, it doesn't make sense for the text field's width to track its content because its content is not "intrinsic".)
The text field's horizontal Content Hugging priority is presumably higher than the Holding priority of the left view of the split view. So, the text field resists "stretching" to be wider than its content at a higher priority than the left view resists being increased in size.
Reduce the text field's horizontal Content Hugging priority and/or increase the left view's Holding priority so that the former is greater than the latter.
I understand the old Struts and Springs method of aligning, sizing and distributing views in Interface Builder. However, I cannot seem to figure out how to evenly distribute views using auto layout with Xcode 5. There was a way to do it using Xcode 4, but that option is gone.
I have 7 buttons arranged in a vertical stack. On a 3.5" layout, it looks great. When I preview the screen in the 4" layout, all of the buttons remain tightly packed and there is a large amount of space below the last button.
I want them to stay the same height, but I want the space between them to be able flex so they can spread out across the screen.
I've been able to get the height of the buttons to flex and fill the space, but that is not my desired behavior. I would like to learn how to use Auto Layout to replace my old Springs behavior, but I can't seem to find any way to do it through Interface Builder.
I'm ok with the top button either being a fixed space from the top edge or a proportional space from the top edge, likewise for the bottom button and the bottom edge. Those are less important to me, I'm good with either.
But I really need to figure out how to evenly distribute the extra space between each of the items in the view.
EDIT Note that in iOS 9 this technique will become unnecessary, because a UIStackView will perform distribution automatically. I'll add another answer explaining how that works.
How to Perform Even Distribution Using Autolayout
The simplest way to do this in Interface Builder alone (rather than constructing constraints in code) is to use "spacer" views:
Position the top and bottom buttons absolutely.
Place spacer views between all the buttons. Use constraints to position them horizontally (centering them horizontally is simplest) and to set their widths.
Make constraints between each button and the spacer view above and below it, with a Constant of 0.
Now select all the spacer views and set their heights to be equal.
The first screen shot shows me setting this up in IB:
I have deliberately not corrected for the "misplaced views" because I want you to see what it looks like while I'm designing the constraints. Here's the result on both a 4 inch and a 3.5 inch screen:
I have left the spacer views black, just to show you how this technique works, but of course in real life you would make them transparent and hence invisible! So the user sees just your buttons, evenly distributed on either height of screen.
The reason for the use of this technique is that although the notion of equality performs the distribution of values you are asking for, constraints can apply equality only between aspects of views; thus we need the extra views (the spacer views) so that we have things we can make equal to other things (here, the heights of the spacer views).
Other Approaches
Obviously, a more flexible approach is to assign the constraints in code. This may sound daunting, but there's a lot of third-party code out there to help you, such as this sort of thing.
For example, if we have a (possibly invisible) superview whose height acts as a boundary to dictate maximum vertical distribution of our four buttons, we can pin their tops to the vertical center of that superview with a constant of 0 but a multiplier of 0.000001, 0.666667, 1.33333, and 2.0 respectively (if we have four buttons); now the buttons will stay vertically distributed even as the superview changes size in response to screen height or whatever. [In Xcode 5.1, it will be possible to set that up in Interface Builder, but in earlier versions of Xcode it is not possible.]
In iOS 9 / Xcode 7 this problem will be trivially solved in IB. Simply select the buttons (or whatever it is you want to distribute vertically) and choose Editor > Embed In > Stack View. Then you simply configure the stack view:
Provide constraints that position and size the stack view itself. For example, pin the four edges of the stack view to the four edges of its superview.
Set the stack view's attributes. In this case we want Vertical axis, Fill alignment, Equal Spacing distribution.
That's all! However, you may be curious about how this works, because it is still possible to do the same thing manually in code. A stack view performs distribution, not by inserting spacer views, but by inserting spacer guides. A guide (a UILayoutGuide) is a lightweight object that behaves like a view for purposes of layout constraints, but is not a view and therefore doesn't have to be made invisible and doesn't carry any of the overhead of a view.
To illustrate, I'll do in code what the stack view is doing. Presume we have four views to distribute vertically. We assign them constraints for everything but their distribution:
They all have absolute height constraints
Their left is pinned to the superview's left, and their right is pinned to the superview's right
The top view's top is pinned to the superview's top, and the bottom view's bottom is pinned to the superview's bottom
Now, presume we have references to the four views as views, an array. Then:
let guides = [UILayoutGuide(), UILayoutGuide(), UILayoutGuide()]
for guide in guides {
self.view.addLayoutGuide(guide)
}
NSLayoutConstraint.activateConstraints([
// guide heights are equal
guides[1].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
guides[2].heightAnchor.constraintEqualToAnchor(guides[0].heightAnchor),
// guide widths are arbitrary, let's say 10
guides[0].widthAnchor.constraintEqualToConstant(10),
guides[1].widthAnchor.constraintEqualToConstant(10),
guides[2].widthAnchor.constraintEqualToConstant(10),
// guide left is arbitrary, let's say superview margin
guides[0].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[1].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
guides[2].leftAnchor.constraintEqualToAnchor(self.view.leftAnchor),
// bottom of each view is top of following guide
views[0].bottomAnchor.constraintEqualToAnchor(guides[0].topAnchor),
views[1].bottomAnchor.constraintEqualToAnchor(guides[1].topAnchor),
views[2].bottomAnchor.constraintEqualToAnchor(guides[2].topAnchor),
// top of each view is bottom of preceding guide
views[1].topAnchor.constraintEqualToAnchor(guides[0].bottomAnchor),
views[2].topAnchor.constraintEqualToAnchor(guides[1].bottomAnchor),
views[3].topAnchor.constraintEqualToAnchor(guides[2].bottomAnchor)
])
(Obviously I could make that code cuter and shorter using loops, but I have deliberately unrolled the loops for clarity, so that you can see the pattern and the technique.)
I have a window whose size I need to change when the user clicks on it. I am using [self setFrame:windowFrame display:YES animate:YES] to accomplish this.
Even though the window successfully changes size (I increase its height), it moves the contents of the window up with it. How do I prevent this from happening? I want the contents to remain in place.
I am on OSX Mountain Lion developing an app for OSX using Objective-C and Cocoa.
EDIT: Constraints and/or Springs and Struts will not work as I need to move the contents around after the window is resized.
Constraints and/or Springs and Struts will not work as I need to move the contents around after the window is resized.
In that case, you should use NSViewAnimation.
A single view animation can actually perform multiple animations to multiple views, and you can even do one to a window, despite the class's name and the fact that windows aren't views in Cocoa.
You create a view animation with initWithViewAnimations:, which takes an array of dictionaries. Each dictionary identifies the target (NSViewAnimationTargetKey) and what to do to it: Either change the target's frame (NSViewAnimationStartFrameKey and NSViewAnimationEndFrameKey) or fade the target in or out (NSViewAnimationEffectKey). For your case, you'll be changing the targets' frames.
When the user does the thing that causes the resize of the window, you'll need to compute the desired overall size of the window (taking care to adjust its frame's position so it doesn't grow off the screen), as well as the new frames—both positions and sizes—of your views. Everything that will move and/or change size, create a dictionary for it and throw it into the array. Then create the view animation.
An NSViewAnimation is a kind of NSAnimation, which provides all the methods for starting and stopping the animation, monitoring its progress, hooking into it, and chaining multiple NSAnimations together. If nothing else, you'll need to start the animation.
If you are using the Interface Builder to build these views, then I believe one approach is to set the "struts and springs." These are available under the "size inspector" and are the red arrows and bars above the "autosizing" label. Play around with these to get the effect that you want, but the general idea is that the arrows control how the size of the view adjusts to changes in the size of the parent view, and the bars control the relationship of the edges of the view to the edges of the parent view as the size changes.
In constraint-based layout, set the views around the edge of your window to be a fixed distance from their superview's edge.
Xcode will infer a lot of resizability from that; if anything still isn't resizing properly, adjust its constraints so that its width and/or height is no longer constant.
The easiest way is to move your views until blue lines show up in the editor. Each blue line corresponds to a rule in the HIG about how things should be lain out, and if you drop the view there, Xcode will create constraints matching those guidelines. For example, if you set a view 20 points from the right edge of its superview, you'll get a blue line for that, and if you drop the view there, you'll create a constraint that the view must remain that distance from that edge.
The superview isn't the only view with which you can create HIG-based constraints. You can also create guideline constraints between sibling views. For example, if you put a button next to another button at the appropriate distance, you'll get a blue line across that distance, and if you drop it, you'll create a constraint that those two buttons must remain that distance from each other.
If you want to do something really custom, the three buttons in the lower-right corner of the nib editor will let you create any constraint you want. What you have selected determines what constraints you can create; the nib editor's outline view will help you make sure you have the selection you want.
You are going to have to iterate through all of your subviews and change their frame positions based on the delta of your window frame.
so if you expand your window frame by 20 in all directions, all your subviews are going to have to increase their frame positions by (20,20) to offset the windows movement.