How to size images for storyboard using auto layout? - xcode6

I'm using Sketch to create images that will be used in my Xcode 6 auto-layout storyboards. However I can not get the image sizes correct. They always appear too large and overflow the storyboard view controller. Is there a way in Xcode to see the dimensions the storyboard expects? Is there a systematic way to do this...rather than trial and error?

Storyboard, especially in auto layout mode, doesn't expect any dimensions – dimensions will depend on device screen (in reality) or on simulated metrics (in Interface Builder in Xcode).
What matters is aspect ratio and presence of three resource files (three sizes – regular, 2x and 3x).
You can see the list of dimensions here:
http://www.paintcodeapp.com/news/iphone-6-screens-demystified
So, let's say you want to insert an image that occupies the whole width of the screen, and the height is chosen automatically so that to keep the aspect ratio. What you could do:
Create images in Sketch with widths of 320, 750 and 1242 pixels. Save them as image.png, image#2x.png, image#3x.png.
Insert image in Interface Builder (Storyboard), add width constraint – equal as superview, instead of height constraint – keep aspect ratio.
If the image looked too big, Interface Builder will complain that preview image doesn't match constraints, you will see a little yellow arrow. Click on it, choose the warning and click again – Xcode will offer you to "Update frame". That will resize the image correctly if necessary. Don't forget to choose correct scaling mode (Aspect fit?) for your image.
Moreover, you can see current width and height of the simulated screen in Metrics tab. But those will change every time you change your preview (simulated) device type.

Related

How to autolayout in Xcode buttons filled with different sized images?

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:

Trouble auto sizing iPhone 5 storyboard to fit iPhone 6

I have developed an app using iPhone 5 storyboard. The storyboard contains many views and I haven't used any constraints on any of the views.
What I am trying to achieve is to make the iPhone 5 storyboard expand to fit on iPhone 6 and 6+ without the need for any constraints, is this possible?
I have read many answer on SO already which lead me to believe that it is possible to get it to work but have not yet succeeded.
I don't have any launch images set, and I ticked the 'Use Size Classes' box for the storyboard.
Why is the storyboard not auto sizing for the iPhone 6. It's driving me crazy.
I hope you can help me,
thanks.
Have you tried using the Autoresizing feature? Uncheck the size classes box and you will see the option to use autoresizing under the measurements section to resize your storyboard for the 6 and 6plus.
http://i.stack.imgur.com/qM4Vu.png
You wont have to use size constraints since you're only making it for the iPhones
Click the "Use Auto Layout" checkbox shown below
Also here is a link to the size of the Launch images you should be using for the 6 and 6 plus.
One way but not recommended. Don't add splash screen for 6 and 6+
If you don't add the splash screen for 6 and 6+ OS will automatically scale all your UI.
The default auto resizing masks, which you probably have, have a fixed top and left margin and a fixed height and width. This would give you all the views packed into the top left corner as you are seeing - the flexibility is all in the right and bottom margins.
You're seriously better off using constraints (even adding the default constraints will probably get you most of the way there) but if you insist on sticking with auto resizing, you need to set fixed left and right margins and flexible width. Height is a bit more difficult, you have to decide which elements will fill the extra space and have flexible height on those.
To ensure that your app supports multiple screen sizes (instead of just scaling up the smaller interface) you should add a launch image .xib file which is much easier than using lots of images.

Springs in Auto Layout: Distribute views evenly, with constraints, in Xcode 5

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.)

How to build a Head Up Display in OpenSceneGraph that resizes depending on the screen's resolution?

I'm pretty new to OpenSceneGraph and I have the following problem:
I'm trying to build a 2D Head Up Display out of several images, so that it can resize depending on the screen's resolution. That means I have extra images for the corners and one image for the bar that connects the corners and so on.
Well, that's the idea. But I have no clue how to do that in OpenSceneGraph.
Can anybody help me?
So, when the window resizes, you'll get an event from osgViewer telling you about the change.
You need to resize your viewport when the window size changes, so your HUD geometry has some idea of what the pixel-size of the display is (most of the HUD examples setup for a nominal 1024x768 screen and then just let that stretch around as the window is resized, pretending like the new viewport is still 1024x768).
Once you've resized the viewpoer, you need to rearrange your geometry. Your corner pieces need to be laid out at the fixed pixel size you want them to always appear, then you need your connecting elements to change size, horizontally or vertically, to fill the space between the corner pieces. You usually rely on texture stretching or repeating to fill the space as the piece of geometry gets stretched.
If none of that makes any sense, I can describe more.

Change size of window in Cocoa?

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.