How do I install and uninstall a UIButton based on size class? - ios

I need a button to be installed in portrait orientation while another button is uninstalled in portrait orientation (any width, any height), while the reverse should occur in landscape orientation (any width, compact height). One of these buttons is part of a UIStackView and the other is part of a UIView.
When in portrait the button in the UIStackView should be installed, but the button inside the UIView should be uninstalled, with the reverse occurring as I mentioned earlier in landscape. Currently I'm checking the userInterfaceIdiom in my view controller for the storyboard, but would like to rely entirely on Interface Builder if possible.
When removing my code (that actually makes it behave correctly), and simply relying on Interface Builder for installing/uninstalling the buttons based on size class, the button installed for landscape orientation always lays out correctly, but when rotating back to portrait, the other button that should now be installed is completely misplaced, out of it's original UIStackView, and that UIStackView that it should stay in, but hasn't, is now expanded to fill in the missing space where that button should have been. When this is happening, there are no warnings or errors from UIKit in the log, and my storyboard shows no conflicts. I'm thoroughly stumped!
At first glance this seems like an easy solution. Simply check/uncheck the install box for size classes of a UI element. Although, even after reading Apple docs and tutorials this is proving to be more difficult and obscure than I expected.
To clarify, I do not have constraints set for the button installed for portrait orientation since it is inside a UIStackView. On the other hand, I do have a few constraints set for the landscape orientation button. Although, the button in the UIStackView is the only one giving me trouble.
The view debugger is not working either in Xcode 7, and I'm receiving the error: warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available. when attempting to use it.
I believe this may be a bug and related to this post: UIStackView properties according to size classes
Your help is greatly appreciated! Thanks.

If you want a component to appear just in a specific size class this is what you do:
Add the constraints to you component using the size class you want it to appear in (wCompact hRegular for all iPhone in portrait and wAny hCompact for all iPhones in landscape). Next make sure that only that size class is ticked in the Attribute Inspector.
Leaving Installed ticked will make the component appear in any size class. You can change the size class of a view controller in a storyboard file by clicking on the option in the center bottom of the screen (see the blue bar at the bottom of the screen, where it says wAny hCompact in the image above).
I hope this helps!
UPDATE
Make sure that the constraints of the components are also set for the correct size class.
From the Document Outline select the constraints of the component and check the size class of the constraint in the Size Inspector. Usually, when you add constraints to a component with a specific Size Class selected in the story board, the constraints will automatically be added for that size class.

Related

How do I get a button to position on the bottom of a view controller in Xcode 7.2?

I used to be able to do this:
UIButton *bigBottomBtn=[[UIButton alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height-60, self.view.frame.size.width, 60)];
I also used to be able to just drag a button onto a storyboard and add a constraint that would hold it to the bottom of the parent.
What is going on with Xcode, Autolayout and Apple for that matter....is my Xcode not working properly? Have I missed a major memo? is Apple just going downhill fast?
Your button-creating code used to work (and still does) if self.view's frame was correct at the time you created the button. Note that the view doesn't necessarily come out of the xib or storyboard with the correct frame; the xib/storyboard contains the view at some design size which might not match the current device. This wasn't as much of a problem when all iPhones had 3.5 inch screens, but became a pretty common problem with the advent of the iPhone 5's 4 inch screen.
The view isn't guaranteed to have its correct frame until its superview's layoutSubviews returns, so if for example you're creating bigBottomBtn in viewDidLoad, that's too early. Many questions on stackoverflow cover this problem. You either need to set the autoresizingMask of the button, or implement layoutSubviews or viewDidLayoutSubviews to update the button's frame, or turn off translatesAutoresizingMaskIntoConstraints and install constraints. Note too that your view can change size if you support rotation, slide over or split view multitasking, or if your view can be the detail view of a UISplitViewController, so it's a bad idea to try to guess the correct frame of the button based on the device's screen size at the moment the button is created.
Note that storyboards now by default use a design size of 600x600, which isn't the size of any device. This is probably because if Apple chose some device's size (say, the iPhone 5's 320x568) as the default, and you happened to use a device of that size as your primary (or only) test device, you could easily forget to think about what your app will look like at other sizes. However, you can explicitly set the design size to some device's size if you want:
I usually use “iPhone 3.5-inch” if I don't specifically need something bigger, because it lets me get the most scenes on the screen simultaneously (and produces the smallest screen shots for stackoverflow).
As for “I also used to be able to just drag a button onto a storyboard and add a constraint that would hold it to the bottom of the parent”, I have good news: you still can. Example:
However, you do need to be careful if you have filled your root view with a table view as appears to be the case in your screen shots. You need to drag the button to the document outline in that case, because if you drop it on the table view, Xcode will assume you want it to be the table view header:
Trying to pin a table view header to the bottom of the screen would be folly.
As for the Editor > Align menu, I have found that the items can be mysteriously inactive, which is frustrating.
Note, though, that only the “Horizontally in Container” and “Vertically in Container” will work (when they work at all) with a single view selected. To use the other items in the menu, you need to have at least two views selected, because the other items align the selected views with each other by setting their frames:
If you only have one view selected, Xcode doesn't know what other view you might want to align it to.
Those menu items are perhaps useful in the springs'n'struts model, but they don't add constraints, and under autolayout you probably want constraints to enforce the alignment at run time.
As far as I know, those menu items have never added constraints, but I'm not going to reinstall Xcode 6 to verify that, because there's a convenient popover that will add constraints corresponding to all of those menu items:
In xcode you always need to add buttons according to its visibility. As you said you need to show button on top of tableView and it should be aligned to bottom. For that You just need to arrange the order of items. as shown in the image below.Provide the layout for the button.

interface builder : make the view the same size as the iphone, to know exactly what constraints to add?

is there a way to have the view from interface builder in Xcode, be the same size as the iphone we use to test the app? The size of the viewcontroller seems to be 600*600. So when I move a UILabel somewhere to the left for example, it will be placed as if it was on the right on my iphone. Which is not easy to set the right constraints.
Do you have some tips to manipulate the items and place them easily? For now, I just align the item with the center point, and move it little by little.
The reason this happens is because of Apple's emphasis of size classes. It looks like a rectangle because whenever you are adding constraints and views, they'll be applied to every size class (i.e. horizontal/compact, vertical/compact, etc).
In english, it means it's applying those changes to run as such on any device.
To create constraints and views for just one size, you'll want to edit the size class you are working with. At the bottom of Xcode where it says "wAny hAny", click that and you can set what device you want to work with:
The whole idea of this is adaptive design, and I've got a post explaining it in more detail here.
The thing is that there is no one correct size for the iphone screen because there are so many different screen sizes. You can set the view size to anything you want in interface builder by clicking on the view and going to simulated metrics -> size but what you really want is autolayout so that your views fit properly on every device.

Xcode 6 Storyboard the wrong size?

Built a new project from scratch in Swift in Xcode 6 (Beta 1) and have seen some strange behaviour with Storyboards and the output that I am viewing.
I have built a simple interface (as shown below) - with properties of View Controller included.
When I run this in the simulator I would expect 'Hello, World' to be central in the user interface - however it seems that this 'Square' is simply being fit into the iPhone screen and thus the wrong view is being shown (see below).
My question is: has anyone else seen this behaviour and how did they fix it?
Thanks!
Do the following steps to resolve the issue
In Storyboard, select any view, then go to the File inspector. Uncheck the "Use Size Classes", you will ask to keep size class data for: iPhone/iPad. And then Click the "Disable Size Classes" button.
Doing this will make the storyboard's view size with selected device.
While Asif Bilal's answer is a simpler solution that doesn't involve Size Classes (which were introduced in iOS 8.) it is strongly recommended you to get used to size classes as they are the future, and you will eventually jump in anyway at some point."
You probably haven't added the layout constraints.
Select your label, tap the layout constraints button on the bottom:
On that menu add width and height (it should NOT be the same as mine) by checking their checkbox and click add constraints. Then Control-drag your label to your main view, and then when you de-click, you should have the options to center horizontally and vertically in container. Add both, and you should be set up.
If you are using Xcode 6 and designing for iOS 8, none of these solutions are correct. To get your iPhone-only views to be sized correctly, don't turn off size classes, don't turn off inferred metrics, and don't set constraints (yet). Instead, use the size class control, which is an easy to miss text button at the bottom of Interface Builder that initially reads "wAny hAny".
Click the button, and choose Compact Width, Regular Height. This resize your views and cover all iPhone portrait orientations.
Apple's docs here: https://developer.apple.com/library/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/SelectingASizeClass.html or search on "Selecting a Size Class in Interface Builder"
In Storyboard, select your ViewController and go to Atribute Inspector. At the very top, under Simulated Metrics you have Size and Orientation properties which are set to Inferred. Change them to desired values.
In order for an application to display properly on another screen size, you also have to setup constraints, as described by Can Poyrazoğlu in the first post.
I had this issue in xcode 6 and there is a way to resolve the resize conflicts. If you select your view, at the bottom you will see an icon that looks like |-Δ-|. If you click on it, you're project will resize for different devices.
Go to Attributes Inspector(right top corner) In the Simulated Metrics, which has Size, Orientation, Status Bar, Top Bar, Bottom Bar properties. For SIZE, change Inferred --> Freeform.
On your storyboard page, go to File Inspector and uncheck 'Use Size Classes'. This should shrink your view controller to regular IPhone size you were familiar with. Note that using 'size classes' will let you design your project across many devices. Once you uncheck this the Xcode will give you a warning dialogue as follows. This should be self-explainatory.
"Disabling size classes will limit this document to storing data for a single device family. The data for the size class best representing the targeted device will be retained, and all other data will be removed. In addition, segues will be converted to their non-adaptive equivalents."
For anyone using XCode 7, it's very easy to design for a specific device size (instead of the default square-ish canvas).
In Interface Builder, select your ViewController or Scene from the left menu. Then under Show the Attributes Inspector, go to the Simulated Metrics, and pick the desired Size from the dropdown menu.
You shall probably use the "Resolve Auto Layout Issues" (bottom right - triangle icon in the storyboard view) to add/reset to suggested constraints (Xcode 6.0.1).

Using UIScrollview in iphone5 compatible app

I have a problem adapting my apps to the new iphone5 layout, I've made the following passes:
Added a retina 4" splash image
Modified the interface in my storyboard with "Size inspector" to change the anchoring of the widgets
Tested the app with iOS6 "retina 4" simulator.
The app works as expected except when the user pop up the keyboard to edit a text, I use the "stretching scrollview" method for this particular situation and this seems not compatibile with the "autosizing" properties of my widgets, here is an example, from iOS6 simulator, without and with keyboard:
And here is what happens:
I'm quite sure this is a coherent behaviour since my main view is stretched so the other items inside it are stretched following their anchoring, the fact is that I'd like to have the same behaviour of my previous fixed position (all widgets anchored to the top left corner) with the iphone5 gui expansion, is this possibile?
How do you solve the problem of showing a keyboard and scroll hidden content in an iphone 5 compatible way?
I have been having similar problems. From what I have found thus far, we may need to remove all constraints on the view within the scrollable view, because it appears that it's contents are being resized along with the frame of the scrollView. I know that setting the internal view's frame manually in viewWillAppear will work, but then you are stuck having a view that is the same size for both iPhone4 and iPhone5 (albeit it will scroll). Or you could "pin height and pin width" of the internalView right there in storyboard.
Two potential approaches that may work. Sorry I can't confirm these as I'm giving up and redesigning around this problem.
1. Programmatically add constraints to your internal view's subviews. The programmatic constraints will allow you to "spring" the distance between your elements proportionally. When adding constraints programmatically, you are given access to a factor called "multiplier" (not to be confused with priority), which I saw someone else on stackoverflow posting about.
2. You can design the internalView in Interface Builder as a separate viewController with it's .xib file, and then use storyboard to load it as an embedded viewController to a "containerView" object, which you would put in place as the new "internal view" of the scrollView. Perhaps then the .xib would first resize to the correct iOS device, and then you could use its frame to resize the containerView.
My advice is create a small test-case of these before implementing, else you end up like me, having spent hours down the wrong path and facing a dead-end.
UPDATE 12/4/12
Make your life easier by NOT setting the ScrollView as the main view of the ViewController.
--Instead, make ViewController.view a dummy/blank view, and embed a scrollView inside that view. Then, embed another view (my CustomView) in the ScrollView. CustomView contains all the visible controls and text boxes and buttons. There is NO HEIGHT CONSTRAINT on CustomView.

IB suvbiews think i'm in portrait even though IB is in landscape

I'm a bit confused and frustrated why Image Views (and UIViews) that I drag onto the IB are always re-sizing and re-positioning themselves rather than get added with the parameters of the IB itself. For example, I have in the IB Attributes window under "Simulated User Interface Elements", changed "Orientation" to "Landscape" and "Status Bar" to "Unspecified" and it's all working like a charm: the IB displays in Xcode as landscape.
But if I drag an Image View onto the IB, it is automatically using the resizing rules of its Size Inspector, as if it expects its "normal" position and size to be Portrait. So as an extra step that seems unnecessary, I have to manipulate the sizing rules for everything I add to IB. Is there an easy way around this, or do we just assume that dragged items onto IB will always consider Portrait as their main orientation.
IB has no customizable default settings that are applied for new objects, so you will have to define the resizing property for each new element you add.
Therefore, in a sense, is like you say, that orientation is by default portrait.
On the other hand, if you do not define the resizing property in IB for Cocoa apps, the layout will not work for any resize of the window; with iOS, things seem to work properly because there is no resize possible, by default. What I am trying to say here is that, in general, it is pretty normal to have to define the resizing property for new elements in IB.

Resources