Tag Archives: autolayout

Where is Update Frames in Xcode 8.1?

A tech author’s work is never done. As soon as he or she completes manuscript and gets it published, the manuscript almost immediately becomes obsolete. In my case, Practical Autolayout for Xcode 8 went obsolete  a day before I published, but I had no idea about a major change in Xcode 8.1.

Until Xcode 8.1, if you wanted to update a frame with new constraints, you had two possibilities. The first was in the pinpinMenuButton and align alignment iconmenu to update as you were setting the constraints.

2016-11-29_06-05-32

The second was a selection in the resolver resolver button 2016-10-01_13-27-48

It seems everyone, including me was not ready for a change Apple made in Xcode 8.1. If you go to look for Update Frames in the resolver resolver button, it is missing:

2016-11-29_06-11-52

So where did it go?

Apple moved this to an icon on the auto layout toolbar and deleted it from the menus.

2016-11-28_07-29-22

If it were me, I wouldn’t have deleted it from the menus in such an abrupt way. Apple did. This Update Frame button  has some different behaviors  from its predecessor on the menu, and I’d like to explain that using some examples from Chapter 3 of Practical Autolayout for Xcode 8

Set up a storyboard that looks something like this with a label Hello Pizza, a text view, and  three  buttons, Pepperoni, Cheese, and Done:

2016-11-29_05-54-14

Select the Hello Pizza label.  Click the pin buttonpinMenuButton in the auto layout toolbar. In the popup, set the top to 0 points, the left to 0 points and the left to 0 points.  Leave Update Frames as None

2016-11-29_05-56-06

Add the 3 constraints. The Hello Pizza Label will show misplacement constraints.

2016-11-29_05-56-32

Press the Update Frames button update frames  and the frame updates.

2016-11-29_06-37-41

This is not always the result. You must have all constraints satisfied before the button will update frames. For example, select the text view. Press the align button alignment iconand center the text view by checking on Horizontally in Container and Vertically in Container.

2016-11-29_05-54-38

Again don’t update frames, but click  Add 2 constraints. You’ll see an ambiguous constraint in red.

2016-11-29_05-55-13

If you click the update frames button nothing happens. Until a frame has no ambiguity(i.e. no red constraint errors), you cannot update it. Most often that is setting a size. For the text box, set an absolute size in the pin menu pinMenuButton  of 175 points in both directions.

2016-11-29_05-57-41

Add the constraints. The errors all turn to misplacements.

 2016-11-29_05-58-39

Once all misplacements, you can update the frame with update frames.

2016-11-29_07-15-35

Priorities are not assumed with the new update frames button. When there is an ambiguity in size between two frames that depend on each other for size, you must specify the a priority for them or set a size.  Take for example these two buttons.

2016-11-29_05-45-35

Pepperoni is pinned to the left margin, the label above it and the text view below it. Cheese is pinned 10 points from Pepperoni, aligned to the top of Pepperoni, and pinned 10 points from the right margin. We’d like to have two buttons that fill the available space.

The option used in Practical Auto Layout for these buttons is to make them the same size. Control drag from Pepperoni to Cheese. A menu appears.

2016-11-29_06-56-57

Shift select Equal Width and Equal Heights, then hit the Add Constraints selection. The ambiguity changes to misplacements.

2016-11-29_06-57-14

Select both the Pepperoni and Cheese buttons. Hit the Update Frame button update frames and two equally sized buttons appear

2016-11-29_06-58-00

The other, more advanced option is to change priority of one of the buttons so they are not equal. Both are by default 250.  Going back to the original ambiguous layout,

2016-11-29_05-45-35

changing the content hugging priority of Pepperoni from 250 to 251 tells auto layout for Pepperoni to keep its size and Cheese to stretch to make up the difference.

2016-11-29_06-56-19

Priorities are covered in detail in Chapter 12 of Practical Autolayout for Xcode 8.

I’ll be updating the book shortly. Until then or if you cannot update your book,  consider this an errata to the versions now available.

practical-autolayout-x8-newsletterPurchase the book for  Kindle and iTunes  here:

get_it_on_ibooks_badge_us_1114

Tab Bar Controllers in Xcode 8 Storyboards

In this lesson, we’ll take a look at tab bar controllers and how to add them in the storyboard.  For more on implementing them completely in code see Swift Swift: Using Tab Bar Controllers in Swift. For more on data sharing once set up in the storyboard, see Passing Data in Tab Bar controllers

The Real Difference between Navigation and Tab Bar Controllers

Before we begin, It’s important to remember the difference between  tab bar and navigation controllers. Navigation controllers are stack based, while tab controllers are parallel in execution. Think of a navigation controller as a stack of cards. You can only play the visible card. If you put a card on top of another card, only the top card is active.

2016-07-06_06-20-22

Now imagine you take several cards and deal them face up. You can play any face up card. They all are active. This is a tab bar controller.

2016-07-06_06-19-45

As we go through lessons on tab bar controllers, it is very important to remember this difference.

Creating From the Template

The easiest way to make a tab bar controller is through Xcode’s template. In Xcode, press Command-Shift-N or File>New>Project. Select the tabbed application.
This will give you a window with two tabs installed with two labels each and a tab item on the bottom of each controller. The template tends to make things more complicated instead of less, so it is rarely used.

Creating From A Single View

The most common way to make a tab bar controller is to start from a single view and embed it in a controller. We’ll try an example of this one in Xcode. Press Command-Shift-N and select Single View. Make a file named SwiftTabBarEmbed, using Swift as the language and with a Universal device. Once created, go over to the Storyboard.  Make sure the Preview setting is  View as: iPhone6s(wC hR) in the lower left corner of the storyboard:

2016-07-05_06-18-15

Change the color of the view controller’s background.

2016-07-05_06-08-41

Select the view controller by clicking the view controller icon or title, and select Editor>Embed in>Tab Bar Controller.

2016-07-05_06-06-10

This will turn the single view controller into the first view controller of the tab bar.

2016-07-05_06-12-22

Add another view controller by dragging out a view controller then control-dragging from the tab bar controller to the new controller. In the pop-up, select under Relationship Segue the view controllers option.

2016-07-05_06-14-57

Another segue appears on the story board.

2016-07-05_06-16-22

You’ll see a second tab in the tab bar controller.

2016-07-05_06-21-14

Adding More Tabs with System Icons

To configure the tab bar icon, go to the Item icon in the  Yellow View Controller (not on the tab view controller) we just made and click it.

2016-07-05_06-23-33

This will bring up in the properties inspector the Tab Bar Item and Bar Item properties. In the Tab Bar Item properties is the System Item drop down. This is where we configure the tab bar button.

2016-07-05_06-25-14

In the System Item menu, Click the drop-down for System Item. you will see a  list of system icons.

2016-07-05_06-26-37

Select Favorites. The Icon changes both on the view controller and the tab bar controller.

2016-07-05_06-28-51

2016-07-05_06-28-26

Click the other view controller’s tab bar, and change the system Icon to Recents.

2016-07-05_06-31-06

2016-07-05_06-31-27

Using  the More Feature

Click on the Preview size Button which reads iPhone 6s(wC hR). A new toolbar appears underneath it. Select the iPad 9.7″.

2016-07-05_06-36-26

The view controllers in the storyboard change to iPads, so you may need to change the zoom level.

2016-07-05_06-40-45

Drag out  six more view controllers, so we have a total of eight controllers.  Change their background colors to make then easily distinguishable.

2016-07-05_06-47-05

Control-drag from the tab bar controller to each new view controller and assign ContactsBookmarksSearch, Downloads, and Most Viewed to the controllers, leaving one more as a custom item. The tab bar controller should look like this:

2016-07-05_06-52-27

Change the Preview mode back to to an iPhone 6s. While your icons may be in a  different order, you will get something like this for the tab bar at the bottom of the phone:

2016-07-05_06-56-32

Compact widths, the width on most phones, cannot handle more than five tabs. If you add more than five tabs, it places a More tab as the fifth tab. What does the More tab do? Build and run as an iPhone 6s in the simulator.

2016-07-05_07-04-24

Tap on the More icon in the lower right. A table appears with the missing tabs.

2016-07-05_07-07-21

 More gives you access to all your tabs. If you tap the tab in the table’s cell, the tab’s controller will appear. Select Downloads, and you get the downloads tab.

2016-07-05_07-10-13

Tabs selected by More act slightly differently than ones in a regular tab. They are embedded in a navigation controller. You’ll see at the top a navigation bar.

2016-07-05_07-14-57

The navigation bar goes back to the More table.  Tap Bookmarks, and notice the navigation bar is not there, then tap More again and the Downloads controller is still there.

   2016-07-05_07-18-21    2016-07-05_07-10-13

Select More  in the navigation bar to go back to the Table view

2016-07-05_07-07-21

User Editing the Tab Bar with More

Without any extra code, tab bar controllers let users customize their tab bars. Tap the Edit button, and you get a configuration view:

2016-07-05_07-23-00

Looking closer, you’ll see that the hidden tabs are highlighted and the visible tabs are dimmed

2016-07-05_07-23-20

Drag the Item tab down to the tab bar. Drop it on top  of Recents. It replaces Recents.

2016-07-05_07-27-25

You can also drag tabs in the tab bar to change the order. Drag Downloads on top of Contacts. Drag  Downloads to the right, swapping it with Bookmarks.  Your tab bar now looks like this:

2016-07-05_07-37-20

I want to add two cautions to this: One of the system icons you can use is a More icon. Be careful when using the More icon in a tab bar. It can cause user confusion between the More tab and your own use for More. Make sure it is clear what you are doing.

The second caution is more insidious. When programming for tab controllers, you can get the tabs from an array. However, the order and visible tabs can change by user request with  the More tab. Avoid hardwiring the tabs by their location in the array since users can change them.

Close the simulator. In the storyboard, delete the Bookmarks, Recents and Favorites view controllers (or their segues if you don’t mind the warnings)  so you get a tab bar like this:

2016-07-05_07-45-54

As we now have five icons, this will keep off the More icon, which requires six tabs to show up. You can reorder the tabs in the tab view controller by drag and drop.   Reorder using drag and drop to this:

2016-07-05_07-50-02

Custom Tab Bar Items

Click on the tab bar for the Item view  controller. We can see all the tab bar properties.

2016-07-05_06-25-14

The lower half has bar item properties, which directly control the title and icon for the tab. We can easily change the text. Change the Bar Item Title to Pie.

2016-07-05_07-55-00

The title changes on the tab bar:

2016-07-05_07-55-36

If we change a System items’s title, it becomes a custom item, and the icon disappears. Do the same to change Downloads to Pizza. Also change Contact to Square.  SquarePizza and Pie have squares for icons.

2016-07-05_08-00-30

Icon Images

Under Title in the properties inspector,  we have a drop down for Image.

2016-07-05_07-55-00

For a custom bar item we can supply the icon. Image icons are not like other images. They are monochrome images,  unlike anything else you have ever seen. They are set not by color but by the alpha value , or transparency of the image. You can make any image here any color, but it will show up as a solid tint color if you select an alpha value of 100% and background color if you select 0% alpha. For example I created the following icons in both high and low resolutions:

gradient bar Pizza and Pie Bat items pizza bar icon pizza bar icon@2x pie bar icon pie bar icon@2

Icons are 30 points by 30 points, which means for retina images make the icon a 60 pixel by 60 pixel image and for low resolution images 30 pixel by 30 pixel. You can download them individually by right clicking the images above, and saving them to a folder.  Use these file names:

Screenshot 2015-01-27 07.37.51

You can also download a.zip file Of these here:Tab Bar Assets

For those not familiar with Apple image naming conventions, low resolution images have a file name. Retina Images have @2x appended to that file name. This tells Xcode to know what resolution it is. We have both 60×60 pixel retina and 30×30 pixel standard images. By loading both into Xcode, the system will use the correct one automatically for the device.
In Xcode’s navigator panel, open up Assets.xcassets. Select all the icon files. Drag them into the center panel in Xcode, which will highlight. Release the mouse button, and you will see a new collection in the image assets.

2016-07-05_08-06-31

Return to the storyboard. On the tab we titled Square,click anywhere on the tab bar.  Select the image drop-down in the tab bar properties and select the gradient bar icon.

2016-07-05_08-09-01

The Gradient bar now replaces the place marker  square:

2016-07-05_08-11-16

Find the Pizza and Pie tab views on the storyboard, and change them the same way. The Tab bar controller now has three custom icons.

2016-07-05_08-12-21

Build and run with the iPhone 6 simulator, and you will see our three icons, with  Pie  highlighted as selected.

Using View Controllers in Tab Bar Controllers

As mentioned earlier, tab bar controllers make a set of single view controllers running parallel to each other. The tab bar switches the view, but the view we leave does not get dismissed, just hidden. there are two uses for such a controller. The first is a series of small independent applications related to each other. Apple’s clock app is an exmaple. The timer, alarm clock, world clock, and stopwatch all are related by a theme of time. All run independently of each other. The second use of Tab bar controllers is to use a shrared data set in different ways. Social media apps like Twitter or Instagram for example use tab bars to have different functions of displaying posts, searches, or displaying notifications that all use the same database. For this second type of use, see see Passing Data in Tab Bar controllers. We’ll look at the first type here.

Basic View Controllers

Connecting a view controller in tab bars is the same as hooking up any other view controller. Make a new view controller class by pressing Command-N. Make a new Cocoa Touch Class view controller named SearchViewController. Change the class code to this.

class SearchViewController: UIViewController {
    var count = 0
    @IBOutlet weak var myLabel: UILabel!
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        myLabel.text = "Count \(count)"
        count += 1
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        count = 1
    }
}

Note how I used viewDidLoad and viewWillAppear here. In tab bar controllers, ViewDidLoad only fires once, when we first load the view controller. Use it for first initializations only. The code above initializes the count to 1. The method viewWillAppear fires every time the view appears, and so we use that to do any updating. This code assumes that this view controller will remain active even when it is not visible.

Go to the storyboard and select the Search view controller on your storyboard. In the identity inspector set the class to SearchViewController.

2016-07-06_05-43-22

On the search view controller  in the storyboard drag a label to the center of the view.

2016-07-06_05-34-14

Set the label font size to 32 points. Click the auto layout align button alignment icon  at the bottom right of the storyboard. In the menu that appears, check Horizontally in Container and Vertically in Container  with values of 0 points. Set Update Frame to Items of New Constraints.

2016-07-06_05-36-05

Add the two constraints. Open up the assistant editor. Drag from the circle next to the outlet to the label to connect it.

2016-07-06_05-49-06

Build and run. Select the search tab, then another tab a few times. You will see the count increase every time you return to the search tab.

2016-07-06_05-51-50     2016-07-05_08-15-11     2016-07-06_05-52-13

Embedding Navigation Controllers in Tab Bar Controllers

You can also embed navigation controllers into tab controllers. Stop the simulator and go back to the storyboard. Close the Assistant editor if it is open. Select the Pizza View Controller’s icon on the storyboard. In the drop down menu, select Editor>Embed in>Navigation Controller

2016-07-06_05-58-46

The view controller changes into a Navigation controller with the tab bar icon. Attached to the navigation controller is a view controller.

2016-07-06_06-05-43

 On the view controller, Double click the center of the navigation controller bar. Change the title to Pizza!!!. Drag a bar button item to the upper left of the controller on the storyboard. Title it More Pizza.

2016-07-06_06-08-10

Add another view controller, next to  the one we just configured. Control-Drag from the bar button item to the new view controller. Set up a show segue. In the new view controller, Drag a Navigation item to the navigation bar. Change the item’s title to More Pizza!!!

2016-07-06_06-10-09

Build and run. Select the Pizza tab and we have our navigation controller. Tap the More Pizza Button. The More Pizza!!! View Appears. Now go to another tab and then back to the Pizza tab. We remain on the More Pizza!!! view.

2016-07-06_06-13-41

You can use navigation controllers inside a tab bar controller to your heart’s content. However, tab bar controllers can only be used once in a project, as the top level controller. Embedding more tab bar controllers does not work.

This is the basics of tab bar controllers. For more information on sharing between the controllers and a more extensive coding example, see Passing Data in Tab Bar controllers.

How to Add Stack Views Programmatically and (almost) avoid AutoLayout

Some people don’t like Interface Builder and like to code instead. Sometimes your layout is so dynamic you need to lay out in code. In either case, programmatic layout of views becomes the answer instead of auto layout. In Xcode 7 Apple introduced stack views. In an earlier post, I introduced stack views in Interface Builder. There are still some problems with stack views in Interface Builder, but those problems do not appear in code. In this lesson I’ll introduce how to use stack views in code.

The Theory

Stacks views are really simple: they are arrays of views with a few properties. You initialize the stackview with an array of views and set a few properties: axis, distribution, fill and spacing. At run time, the views create constraints the fulfill those requirements.

By doing this you can almost avoid auto layout with one exception: you need to use auto layout to layout the stack view on the superview. In our lesson, we’ll layout our stack view over the entire view and then  have a view that works with lots of embedded views and stack views.

Set up the Project

Create a new Universal project in Swift called StackViewCodeDemo. Since Xcode no longer marks the launchscreen, add a label to the launchscreen.storyboard with the title StackViewCodeDemo. I usually center this by clicking the align menu button and then center horizontally and vertically in the container and updating the constraints like this:

center alignment

Since the is programmatic, we need nothing on the storyboard.

The Button Generator

I’m going to use a series of buttons for my view objects. Go to the ViewController.swift code and add the following declarations to the class:

//MARK: Properties
let colorDictionary = [
    "Red":UIColor(
        red: 1.0,
        green: 0.0,
        blue: 0.0,
        alpha: 1.0),
    "Green":UIColor(
        red: 0.0,
        green: 1.0, 
        blue: 0.0, alpha: 1.0),
    "Blue":UIColor(
        red: 0.0,
        green: 0.0,
        blue: 1.0,
        alpha: 1.0),
]

This dictionary gives us a color name for a key and a UIColor for a value. Now add the follow function to the class:

//MARK: Instance methods
func colorButton(
     withColor color:UIColor,
     title:String) -> UIButton
{
   let newButton = UIButton(type: .System)
   newButton.backgroundColor = color
   newButton.setTitle(
       title,
       forState: .Normal)       
   newButton.setTitleColor(
       UIColor.whiteColor(),
       forState: .Normal)
   return newButton
}
 

I’m keeping this simple. I built a method to make a button quickly with certain properties set. I left off the action, but you can certainly put it in here. I did this so I can iterate through my dictionary and make buttons. Make another method with this code:

 func displayKeyboard(){
//generate an array of buttons
    var buttonArray = [UIButton]()
    for (myKey,myValue) in colorDictionary{
         buttonArray += [colorButton(
             withColor: myValue,
             title: myKey)
         ]
}

We have an array of buttons that take their color and title from the dictionary.

Making a Stack View

We are now ready to make a stack view and add it to the superview. I’ll make one that will have the three buttons next to each other. Under the displayKeyboard we just wrote, add the following:

let stackView = UIStackView(arrangedSubviews: buttonArray)
stackView.axis = .Horizontal
stackView.distribution = .FillEqually
stackView.alignment = .Fill
stackView.spacing = 5
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)

The arrangedSubviews parameter of the UIStackView initializer takes an array of UIView objects and makes a stack view from it. We set the properties for the stack view, and shut off the autoresizing mask. I used a .Fill distribution which will stretch the buttons vertically to take the entire view. The distribution property makes equal width buttons. I set the buttons 5 points away from each other.

This stack view needs autolayout, which is why it was critical to shut off the autoresizing mask. We’ll lay out the stack view to be the view with a margin. I pinned the view to the left and right margins which are 20 points from the left and right sides, and 30 points above and below the top and bottom of the superview. Add this to your code:

//autolayout the stack view - pin 30 up 20 left 20 right 30 down
        let viewsDictionary = ["stackView":stackView]
        let stackView_H = NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|-20-[stackView]-20-|",  //horizontal constraint 20 points from left and right side
            options: NSLayoutFormatOptions(rawValue: 0),
            metrics: nil,
            views: viewsDictionary)
        let stackView_V = NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|-30-[stackView]-30-|", //vertical constraint 30 points from top and bottom 
            options: NSLayoutFormatOptions(rawValue:0),
            metrics: nil,
            views: viewsDictionary)
        view.addConstraints(stackView_H)
        view.addConstraints(stackView_V)

I’ll leave this code as-is. It works fine for a template to use the entire view for a stack View. If you want to know more about Auto layout in code, see my post on it.

Finally add the method to the viewDidLoad

 override func viewDidLoad() {
        super.viewDidLoad()
        displayKeyboard()
    
    }

Build and run. You will have three buttons:

2015-11-11_07-31-41

Rotate and the buttons automatically change size and shape.

2015-11-11_07-31-42

Nesting Stack Views

Once we have one stack view, we can also nest stack views. comment out the following code:

/*
let stackView = UIStackView(arrangedSubviews: buttonArray)
        stackView.axis = .Horizontal
        stackView.distribution = .FillEqually
        stackView.alignment = .Fill
        stackView.spacing = 5
        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)
        */

Add underneath it the following code:

let subStackView = UIStackView(arrangedSubviews: buttonArray)
subStackView.axis = .Horizontal
subStackView.distribution = .FillEqually
subStackView.alignment = .Fill
subStackView.spacing = 5
//set up a label
let label = UILabel()
label.text = "Color Chooser"
label.textColor = UIColor.whiteColor()
label.backgroundColor = UIColor.blackColor()
label.textAlignment = .Center

let blackButton = colorButton(withColor: UIColor.blackColor(), title: "Black")

I made a stack view like our last stack view, a label with white text on a black background, and a black button. Under that code add this:

let stackView = UIStackView(arrangedSubviews: [label,subStackView,blackButton])
stackView.axis = .Vertical
stackView.distribution = .FillEqually
stackView.alignment = .Fill
stackView.spacing = 10
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)

We make a vertical stack view with the three views we defined. The order of the array is left to right in horizontal and top to bottom in vertical. I kept the same distribution and alignment as our first example, but added 10 points between the vertical view. Since our auto layout constraints for stackView are already set, we are ready to build and run. Check the view in both portrait and landscape.

2015-11-11_07-49-21

2015-11-11_07-49-32

Without a lot of coding for layout, stack views can make some quick adaptive layouts with a minimal amount of auto layout. Apple’s documentation encourages using stack views for the easiest and most adaptive layout, making coding for devices from a iPhone to an AppleTV easy. I kept this simple. In a real app, you probably want to add actions and have your views defined outside the displayKeyboard method as properties. You might want to play around with that and with changing the properties of the stack view to see the variation you can get with a stack view.

The Whole Code

//
//  ViewController.swift
//  StackViewCodeDemo
//
//  Created by Steven Lipton on 11/11/15.
//  Copyright © 2015 MakeAppPie.Com. All rights reserved.
//

import UIKit



class ViewController: UIViewController {
    //MARK: Properties
   
    let colorDictionary = [
        "Red":UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0),
        "Green":UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0),
        "Blue":UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0),
    ]
    
    //MARK: Instance methods
    func colorButton(withColor color:UIColor, title:String) -> UIButton{
        let newButton = UIButton(type: .System)
        newButton.backgroundColor = color
        newButton.setTitle(title, forState: .Normal)
        newButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        return newButton
    }
    
    
    func displayKeyboard(){
                 //generate an array
       
        
        var buttonArray = [UIButton]()
        for (myKey,myValue) in colorDictionary{
            buttonArray += [colorButton(withColor: myValue, title: myKey)]
        }
        /* //Iteration one - singel stack view
        let stackView = UIStackView(arrangedSubviews: buttonArray)
        stackView.axis = .Horizontal
        stackView.distribution = .FillEqually
        stackView.alignment = .Fill
        stackView.spacing = 5
        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)
        */
        
        //Iteration two - nested stack views
        //set up the stack view
        let subStackView = UIStackView(arrangedSubviews: buttonArray)
        subStackView.axis = .Horizontal
        subStackView.distribution = .FillEqually
        subStackView.alignment = .Fill
        subStackView.spacing = 5
        //set up a label
        let label = UILabel()
        label.text = "Color Chooser"
        label.textColor = UIColor.whiteColor()
        label.backgroundColor = UIColor.blackColor()
        label.textAlignment = .Center
        
        let blackButton = colorButton(withColor: UIColor.blackColor(), title: "Black")
        
        let stackView = UIStackView(arrangedSubviews: [label,subStackView,blackButton])
        stackView.axis = .Vertical
        stackView.distribution = .FillEqually
        stackView.alignment = .Fill
        stackView.spacing = 10
        stackView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(stackView)
    
        //autolayout the stack view - pin 30 up 20 left 20 right 30 down
        let viewsDictionary = ["stackView":stackView]
        let stackView_H = NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[stackView]-20-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)
        let stackView_V = NSLayoutConstraint.constraintsWithVisualFormat("V:|-30-[stackView]-30-|", options: NSLayoutFormatOptions(rawValue:0), metrics: nil, views: viewsDictionary)
        view.addConstraints(stackView_H)
        view.addConstraints(stackView_V)
    }
    //MARK: Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        displayKeyboard()
    
    }



}


Swift Swift: Using NSTimer to Make a Timer or Alarm

frame 0730 042315With the launch of the Apple Watch it’s time for timers in iOS and WatchKit. Learning to use timers is a very important skill for most developers. There are many places we need to schedule regular intervals of time to do things. In my WatchKit series I’m writing a workout interval timer which tells the user when to switch intervals. Timers can tell the system to do more than just alarms. If you are not using SpriteKit, Games and animations need the use of  timers to control the frames per second of animation. In this lesson, we’ll look at NSTimer, and what we can do with the timer. There are two ways most people use it: for a single event or for repeated events. We’ll discuss both.

Set up the Storyboard

Create a new Project named SwiftPizzaTimer in a single view template with Swift as the language. Drag three labels, three buttons and a switch to the storyboard. Arrange the storyboard like this.

Screenshot 2015-04-23 05.30.11

You can use Auto layout in the Width:any Height:any size class, or set you size class to Width:compact, height:any and just drag and drop your controls. To use auto layout, do the following:
Drag one label to the storyboard. Title it Pizza Timer. Give it a light gray background with black letters, center alignment and a font size of 46 point. Pin the label 0 points up 0 left and 0 right. Set the height to 64 points, and select to Update the frame of new Constraints.
Drag two buttons under the label and next to each other. On the button to the left, title it Start, make the font black with a size of 46 points and a green background. On the right title the label Stop with a size of 46 points, white lettering and a red background. Pin the Start label 15 points up, and 0 left. Do not update the frames. Pin the Stop label 0 left and 0 right. Select the Pizza Timer label and the Start button. In the pin menu select Equal Heights. Select the Start button and the Stop button. In the pin menu, select Equal widths and Equal Heights. In the align menu with both Start and Stop still selected, select Top edges, and make sure the value is 0. Also select the Update Frames Items of New Constraints.

Drag another button to the storyboard. Label it Reset, with a blue background, white lettering, and a font size of 46 points. Pin the Reset button 0 left,0,right, 20 down, but do not update constraints yet. Select both the Pizza Timer label and the Reset button and in the pin menu select Equal Heights and set Update Frames to Items of New Constraints.

Drag a switch to the storyboard. Set its state to off in the attributes inspector. In the align menu, Align the switch to Horizontal Center in Container. Pin the Switch 15 up and select for Update Frames Items of new Constraints.

Drag two more labels to the storyboard position one to the left of the switch labeled Up and one to the right Down. Give both a font color of White and a font of 36 points. Right justify the Up label. pin the Up Label 0 left and 15 right. Select the label and the switch, and in the align menu Align to centers, and Update Frames of new constraints. Select the down label. Pint the down label 15 left and 0 right. Select both the Down label and the switch. In the align menu Align to centers, and Update Frames of new constraints. Your finished layout should be this:

 Screenshot 2015-04-23 06.17.07

Open the assistant editor and control-drag the outlets and actions. Start with the Pizza Timer label. Control drag and make an outlet timerLabel.

@IBOutlet weak var timerLabel: UILabel!   //label on top of the view

From the switch make an outlet countingDown

@IBOutlet weak var countingDown: UISwitch! //for use in iteration 2

From the three buttons control drag to make three actions: startTimer, stopTimer and resetTimer respectively:

@IBAction func startTimer(sender: UIButton) {
}
@IBAction func stopTimer(sender: UIButton) {
}
@IBAction func resetTimer(sender: UIButton) {
}

Make an Alarm

The most useful class method for NSTimer is scheduledTimerWithTimeInterval. It has a form like this:

class func scheduledTimerWithTimeInterval(
     ti: NSTimeInterval, 
     target aTarget: AnyObject, 
     selector aSelector: Selector, 
     userInfo: AnyObject?,  
     repeats yesOrNo: Bool) -> NSTimer 

The first parameter gives a time in seconds that the timer will run for. At the end of that time, it will call a method set by the second two parameters. If there is information that needs passing to that method, we do so in the userInfo parameter, which stores the information in the timer.  Often this will be a dictionary of several values, though it can be any object. The last parameter tells us if we will repeat the timer or just end.

Let’s add a timer to our code, change startTimer to this:

    @IBAction func startTimer(sender: AnyObject) {
        timerLabel.text = "Timer Started"
        timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
            target: self,
            selector: "timerDidEnd:",
            userInfo: "Pizza Done!!",
            repeats: false)
    }

Our timer schedules a time of timeInterval, and when done runs a method timerDidEnd, then stops. This is the classic alarm clock method of doing something. You set an alarm and it goes off at some time with a given message, then dies. Xcode complains we have not defined  interval or timer. Just below your outlet declarations add this

var timer = NSTimer() //make a timer variable, but don't do anything yet
let timeInterval:NSTimeInterval = 10.0

Our next step is declaring a method timerDidEnd. Add this to the code.

//MARK: - Instance Methods
    func timerDidEnd(timer:NSTimer){
        //first iteration of timer
          timerLabel.text = timer.userInfo as? String
    }

When the timer fires, It calls this method. We tell the user that the timer completed  with the Pizza Ready!! message. Because we set repeat to false, the timer will dismiss itself after this call. If we need any information about the timer, including whatever we stored in userInfo, we have a parameter in our method to access it, which we have our completion message. Since userInfo is of type AnyObject, we will  need to downcast it correctly before use.

Add the following to the stopTimer method:

@IBAction func stopTimer(sender: AnyObject) {
        timerLabel.text = "Timer Stopped"
        timer.invalidate()
    }

In our stopTimer method, we use the NSTimer method invalidate to stop and destroy the timer.  Once stopped, the app gives the user feedback to tell them the timer stopped.

Build and run. When the app loads, tap the start button. nothing happens for ten seconds, when you get this:

Screenshot 2015-04-23 06.53.52

Using Repeating Timers

Timers only show that a time event happened. In the example above that was pretty boring. Let’s change the code for more user feedback and have the timer count up or down the ten seconds of our timer. To do this, we’ll use the most common way of using a timer with repeat set to true. The strategy here is having lots of short timing events. At each time event we do some updating and check if we are at our target time, when we will shut down our timer and do our exit activities like we did with our first example.

Change the variables to this:

var timer = NSTimer() //make a timer variable, but don't do anything yet
let timeInterval:NSTimeInterval = 0.05 //smaller interval
let timerEnd:NSTimeInterval = 10.0 //seconds to end the timer
var timeCount:NSTimeInterval = 0.0 // counter for the timer

The timer is the same, but we changed our interval to 0.05 seconds. every 0.05 seconds we will update the timerLabel with a new time. There is a balance here, which you might want to experiment with. If you make too big an interval, there will be inaccuracy with your visible timer. If you make too small an interval, you use a large amount of resources. If you use too many, you might have an internal inaccuracy to your timer as well and the app will be unresponsive. My general rule is to set my interval for a half of the last digit of accuracy you are displaying. I am going to 0.1 seconds accuracy on my label, so I set the interval to 0.05.

Since interval is no longer telling me when ten seconds is up we need another constant to tell us that,  assigned to timerEnd. I also assigned a variable timeCount. Every time timer fires, the app will either add or subtract the timeInterval from timeCount. When I reach zero on a countdown timer or 10 on a count up timer I stop. Change your timerDidEnd method to this:

func timerDidEnd(timer:NSTimer){
        if countingDown.on{
            //timer that counts down
            timeCount = timeCount - timeInterval
            if timeCount <= 0 {  //test for target time reached.
                timerLabel.text = "Pizza Ready!!"
                timer.invalidate()
            } else { //update the time on the clock if not reached
                timerLabel.text = timeString(timeCount)
            }
        } else {
            //timer that counts up
            timeCount = timeCount + timeInterval
            if timeCount >= timerEnd{  //test for target time reached.
                timerLabel.text = "Pizza Ready!!"
                timer.invalidate()
            } else { //update the time on the clock if not reached
                timerLabel.text = timeString(timeCount)
            }

        }

We use the switch countingDown to decide if we count up or down. If we count up, we add the time interval. If counting down, we subtract the time interval. We look for our ending condition. If true, we exit as we defined it in the last example. If not at the ending condition, we update the time display.

The time is in seconds, We need to format it to a form usable by most humans, which we do in the function timeString. Add this code:

  func timeString(time:NSTimeInterval) -> String {
    let minutes = Int(time) / 60
    let seconds = time - Double(minutes) * 60
    let secondsFraction = seconds - Double(Int(seconds))
    return String(format:"%02i:%02i.%01i",minutes,Int(seconds),Int(secondsFraction * 10.0))
}

We use the truncation power of integers to get minutes and seconds we can use in our return string of mm:ss.s. minutes takes a timeinterval of seconds and makes it an integer then divides by 60 seconds. seconds subtracts out that many seconds. We get a digit for the tenth of a second by subtracting the number of seconds from the integer number of seconds.

We now have a display when the timer fires. We have not yet implemented a reset for the timer. Add this to your code:

    //MARK: - Instance Methods
    func resetTimeCount(){
        if countingDown.on{
            timeCount = timerEnd
        } else {
            timeCount = 0.0
        }
    }

Depending on the switch, we have a different starting point. Counting down, we count down from timerEnd to 0. We do the reverse for counting up, starting at 0. Now that we have a reset function, we can define the action for the reset button.

@IBAction func resetTimer(sender: AnyObject) {
        timer.invalidate()
        resetTimeCount()
        timerLabel.text = timeString(timeCount)
    }

Whenever we reset, we will stop the timer first. For a reset we clear the count on the timer, the update timerLabel with the reset time. Our final change is to startTimer. Change the code to this:

     @IBAction func startTimer(sender: AnyObject) {
        if !timer.valid{ //prevent more than one timer on the thread
            timerLabel.text = timeString(timeCount) //change to show clock instead of message
            timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
                target: self,
                selector: "timerDidEnd:",
                userInfo: nil,
                repeats: true) //repeating timer in the second iteration
        }
    }
 

We changed the timer to be a repeating timer by changing repeats to false. We can build and run.

timerDemo

We have a working timer. You can change the countdown or count up by tapping the switch.

One more bug — Using Flags in Timers

It’s important for debugging to check all possibilities of use. If we reset the timer, then change our count direction, the timer fails. The timer believes it is already done. When we reset, we clear the counter. When we change the switch, we change the terminating value to be the same as the start value and the timer thinks it’s finished. We’ll need to change our start value when the switch changes and the timer is reset.

Go to the storyboard and open the assistant editor.  Control drag from the switch to the code. Make a new action countingDown. Add the following code to the action:


    @IBAction func countingDown(sender: UISwitch) {
        if !isTiming {
            resetTimeCount()
            timerLabel.text = timeString(timeCount)
        }
    }

We use a flag isTiming to decide if the timer is in the middle of a count. If it is not, which will happen after the timer is done or a reset and when we change the switch we reset the count. Otherwise we leave the count alone. Flags in timer are common. they are good ways of indicating the state of the timer while it is running repetitively, much in the same way valid works for a single timer. We still need a little setup for this to work. Add the variable to our properties at the top of the class:

var isTiming = false

In starTimer, add isTiming = true to the if clause code block and isTiming = false to resetTimer, and just under the two timer.invalidate() in timerDidEnd
Build and run. Now the timer works right.

The Whole Code

Iteration 1 of timer

//
//  ViewController.swift
//  SwiftPizzaTimer
//
//  Created by Steven Lipton on 4/22/15.
//  Copyright (c) 2015 MakeAppPie.Com. All rights reserved.
//
//  Iteration 1 of the timer - a single time
//

import UIKit

class ViewController: UIViewController {
    //iteration 1 of the timer

    //MARK: - Outlets and properties

    @IBOutlet weak var timerLabel: UILabel!
    @IBOutlet weak var countingDown: UISwitch! //for use in iteration 2

    var timer = NSTimer() //make a timer variable, but do do anything yet
    let timeInterval:NSTimeInterval = 10.0

    //MARK: - Actions
    @IBAction func startTimer(sender: UIButton) {
        timerLabel.text = "Timer Started"
        timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
            target: self,
            selector: "timerDidEnd:",
            userInfo: "Pizza Done!!",
            repeats: false)
    }
    @IBAction func stopTimer(sender: UIButton) {
        timerLabel.text = "Timer Stopped"
        timer.invalidate()
    }
    @IBAction func resetTimer(sender: UIButton) {
    }

    //MARK: - Instance Methods
    func timerDidEnd(timer:NSTimer){
        //first iteration of timer
        timerLabel.text = "Pizza Ready!!"
    }
   }

Iteration 2 count up and down timer

//
//  ViewController.swift
//  SwiftPizzaTimer
//
//  Created by Steven Lipton on 4/22/15.
//  Copyright (c) 2015 MakeAppPie.Com. All rights reserved.
//
//  Iteration 1 of the timer - a single time
//

import UIKit

class ViewController: UIViewController {
    //iteration 2 of the timer

    //MARK: - Outlets and properties

    @IBOutlet weak var timerLabel: UILabel!

    @IBOutlet weak var countingDown: UISwitch!

    var timer = NSTimer() //make a timer variable, but do do anything yet
    let timeInterval:NSTimeInterval = 0.05
    let timerEnd:NSTimeInterval = 10.0
    var timeCount:NSTimeInterval = 0.0
    //MARK: - Actions

    @IBAction func startTimer(sender: UIButton) {

        if !timer.valid{ //prevent more than one timer on the thread
            timerLabel.text = timeString(timeCount)
            timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval,
                target: self,
                selector: "timerDidEnd:",
                userInfo: "Pizza Done!!",
                repeats: true) //repeating timer in the second iteration
        }
    }

    @IBAction func countingDown(sender: UISwitch) {
        if !timer.valid{ //if we stopped an
            resetTimeCount()
        }
    }
    @IBAction func stopTimer(sender: UIButton) {
        //timerLabel.text = "Timer Stopped"
        timer.invalidate()
    }

    @IBAction func resetTimer(sender: UIButton) {
        timer.invalidate()
        resetTimeCount()
        timerLabel.text = timeString(timeCount)
    }

    //MARK: - Instance Methods
    func resetTimeCount(){
        if countingDown.on{
            timeCount = timerEnd
        } else {
            timeCount = 0.0
        }
    }

    func timeString(time:NSTimeInterval) -> String {
    let minutes = Int(time) / 60
    //let seconds = Int(time) % 60
    let seconds = time - Double(minutes) * 60
    let secondsFraction = seconds - Double(Int(seconds))
    return String(format:"%02i:%02i.%01i",minutes,Int(seconds),Int(secondsFraction * 10.0))
}

    func timerDidEnd(timer:NSTimer){
        //timerLabel.text = timer.userInfo as? String

        if countingDown.on{
            //timer that counts down
            timeCount = timeCount - timeInterval
            if timeCount <= 0 {  //test for target time reached.
                timerLabel.text = "Pizza Ready!!"
                timer.invalidate()
            } else { //update the time on the clock if not reached
                timerLabel.text = timeString(timeCount)
            }

        } else {
            //timer that counts up
            timeCount = timeCount + timeInterval
            if timeCount >= timerEnd{  //test for target time reached.
                timerLabel.text = "Pizza Ready!!"
                timer.invalidate()
            } else { //update the time on the clock if not reached
                timerLabel.text = timeString(timeCount)
            }

        }

    }

   }

Tab Bar Controllers in Storyboards

[Updated to Swift 2.0/iOS9 9/21/15 SJL]
While Navigation controllers often have the limelight when it comes to Xcode controllers, Tab Bar controllers are great for independent tasks in the same app or for different ways of working with the same model. In this lesson, we’ll take a look at tab bar controllers and how to add them in the storyboard.  For more on implementing them completely in code see Swift Swift: Using Tab Bar Controllers in Swift. For more on data sharing once set up in the storyboard, see Passing Data in Tab Bar controllers

Creating from the Template

The easiest way to make a tab bar controller is through Xcode’s template. In Xcode, press Command-Shift-N or File>New>Project. Select the tabbed application.
This will give you a window with two tabs installed with two labels each and a tab item on the bottom of each controller. The template tends to make things more complicated instead of less, so it is rarely used.

Creating From A Single View

The most common way to make a tab bar controller is to start from a single view and embed it in a controller. We’ll try an example of this one in Xcode. Press Command-Shift-N and select Single View. Make a file named SwiftTabBarEmbed, using Swift as the language and with a Universal device. Once created, go over to the Storyboard. Select the view controller by clicking the view controller icon or title, and select Editor>Embed in>Tab Bar Controller.

Screenshot 2015-01-27 05.38.51

This will turn the single view controller into the first view controller of the tab bar.

Screenshot 2015-01-27 05.40.04

Add another view controller by dragging out a view controller then control-dragging from the tab bar controller to the new controller. In the popup, select under Relationship Segue the view controllers option.

Screenshot 2015-01-27 06.05.53

A segue appears on the story board. You’ll see a second tab in the tab bar controller.

Screenshot 2015-01-27 06.08.46

Adding More Tabs with System Icons

To configure the tab bar icon, go to the Item icon in the View Controller (not on the tab view controller) we just made and click it. This will bring up in the properties inspector the Tab Bar Item and Bar Item properties. In the Tab Bar Item properties is the System Item drop down. This is where we configure the tab bar button.

Screenshot 2015-01-27 07.08.34

In the System Item menu, Click the drop-down for System Item. you will see a  list of system icons.

Screenshot 2015-01-27 06.24.23

Select Favorites. The Icon changes both on the view controller and the tab bar controller.

Screenshot 2015-01-27 06.29.10
Click the other view controller’s tab bar, and change the system Icon to Recents.
Drag out six more view controllers, so we have a total of eight controllers. Control-drag from the tab bar controller to each new view controller and assign Contacts ,Bookmarks ,Search, Downloads ,and Most Viewed to the controllers, leaving one as a custom item. The tab bar controller should look like this:

Screenshot 2015-01-27 06.41.22

Using More

Set the simulator to an iPhone 6. Build and run. While your icons may be in a  different order, you will get something like this for the tab bar at the bottom of the phone:

Screenshot 2015-01-27 06.43.18

We get an extra tab we did not set up titled More. Tap on the More icon.

Screenshot 2015-01-27 06.47.05

Compact widths cannot handle more than five tabs. If you add more than five tabs, it places a More tab as the fifth tab and makes this table view for you. If you tap the tab in the table’s cell, the tab’s controller will appear.

Without any more code, tab bar controllers let users customize their tab bars. Tab the Edit button, and you get a configuration view:

Screenshot 2015-01-27 06.53.13

Drag one of the icons down to the tab bar. It replaces one tab. You can also drag tabs in the tab bar to change the order. Try getting the tab bar to look like in the above screenshot, then tap Done. Your tab bar now looks like this:

Screenshot 2015-01-27 07.01.21

One of the system icons you can use is a More icon. Be careful when using the More icon in a tab bar. It can cause user confusion between the More tab and your own use for More.

Close the simulator. In the storyboard, delete three view controllers so you get a tab bar like this:

Screenshot 2015-01-27 07.05.10

Since we now have five icons, this will keep off the More icon.

Custom Tab Bar Items

Click on the tab bar for the one custom controller.We can see all the tab bar properties.

Screenshot 2015-01-27 07.08.34

The lower half has bar item properties, which directly control the title and icon for the tab. We can easily change the text. Change the Bar Item Title to Square.

Screenshot 2015-01-27 12.36.47

The title changes on the tab bar:

Screenshot 2015-01-27 12.37.13

If we change a System items’s title, it becomes a custom item, and the icon disappears. Click on the Contacts Icon. Change the title to Pizza. Do the same to change Downloads to Pie. All become squares.

Icon Images

Under Title in the properties inspector,  we have a drop down for Image. For a custom bar item we can supply the icon. Image icons are not like other images. They are monochrome images,  unlike anything else you have ever seen. They are set not by color but by the alpha value , or transparency of the image. You can make any image here any color, but it will show up as a solid tint color if you select an alpha value of 100% and background color if you select 0% alpha. For example I created the following icons in both high and low resolutions:

gradient bar Pizza and Pie Bat items pizza bar icon pizza bar icon@2x pie bar icon pie bar icon@2

Icons are 30 points by 30 points, which means for retina images make the icon a 60 pixel by 60 pixel image and for low resolution images 30 pixel by 30 pixel. You can download them individually by right clicking the images above, and saving them to a folder.  Use these file names:

Screenshot 2015-01-27 07.37.51

You can also download a.zip file Of these here:Tab Bar Assets

For those not familiar with Apple image naming conventions, low resolution images have a file name. Retina Images have @2x appended to that file name. This tells Xcode to know what resolution it is. We have both 60×60 pixel retina and 30×30 pixel standard images. By loading both into Xcode, the system will use the correct one automatically for the device.
In Xcode’s navigator panel, open up images.xassets. Select both gradient bar icon files. Drag them into the center panel in Xcode, which will highlight, and the number 2 will appear next to your cursor. Release the mouse button, and you will see a new collection in the image assets.

Screenshot 2015-01-27 07.47.43

Do the same for the pie bar and pizza bar files Select the pizza bar.png and pizza bar@2x.png files and drag them to the assets manager. Do the same for the pie bar.png and pie bar@2x.png buttons.
Return to the storyboard. On the tab we titled Square,click anywhere on the tab bar.  Select the image drop-down in the tab bar properties and select the gradient bar icon.

Screenshot 2015-01-27 07.56.11

Find the Pizza and Pie tab views on the storyboard, and change them the same way. The Tab bar controller now has three custom icons.

Screenshot 2015-01-27 08.00.29

Build and run with the iPhone 6 simulator, and you will see our three icons, with one highlighted as selected.

Using View Controllers in Tab Bar Controllers

Tab Bar controllers make a set of single view controllers running parallel to each other. The tab bar switches the view, but the view we leave does not get dismissed, just hidden. there are two uses for such a controller. The first is a series of small applications related to each other. Apple’s clock app is an exmaple. The timer, alarma clock, world clock, and stopwatch all are related by a theme of time. All run independently of each other. The second use of Tab bar controllers is to use a shrared data set in different ways. Social media apps like Twitter or Instagram for example use tab bars to have different functions of displaying posts, searches, or displaying notifications that all use the same database. For this second type of use, see see Passing Data in Tab Bar controllers. We’ll look at the first type here.

Basic View Controllers

You already know how to hook up a view controller for a tab bar. First make a new view controller class by pressing Command-N. Make a new Cocoa Touch Class view controller named SearchViewController. Change the class code to this.

class SearchViewController: UIViewController {

    var count = 0
    
    @IBOutlet weak var myLabel: UILabel!
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        myLabel.text = String(format:"Count %i",count++)
    }
}

I did not use viewDidLoad here. In tab bar controllers, ViewDidLoad only fires once, when we first load the view controller. The method viewWillAppear fires every time the view appears, and so we use that to do any updating. This code assumes that this view controller will remain active even when it is not visible.

Go to the storyboard and select the Search view controller on your storyboard. In the identity inspector set the class to SearchViewController. On the view in the storyboard drag a label to the upper let and size it up a bit.

2015-09-21_08-07-00

Open up the assistant editor. Drag from the circle next to the outlet to the label to connect it. Build and run. Select the search tab, then another tab a few times. You will see the count increas every time you return to the search tab.

2015-09-21_08-19-57

Embedding Navigation Controllers in Tab Bar Controllers

You can also embed navigation controllers into tab controllers. Stop the simulator and go back to the storyboard. Close the Assistant editor if it is open. Select the Pizza View Controller’s icon on the storyboard. In the drop down menu, select Editor>Embed in>View Controller

2015-09-21_08-23-16

The view controller changes into a Navigation controller with the tab bar icon.

2015-09-21_08-25-05

Attached to the navigation controller is a view controller. Double click the center of the navigation controller bar. Change the title to Pizza!!. Drag a bar button item to the upper left of the controller on the storyboard. Title it More Pizza.

2015-09-21_08-25-33

Add another view controller, below the one we just configured. Control-Drag from the bar button item to the new view controller. Set up a show segue. In the new view controller, Drag a Navigation item to the navigation bar. Change the item’s title to More Pizza!!!

2015-09-21_08-28-11

Build and run. Select the Pizza tab and we have our navigation controller.

Tap the More Pizza Button. The More Pizza!!! View Appears. Now go to another tab and then back to the Pizza tab. We remain on the More Pizza!!! view.

You can use navigation controllers inside a tab bar controller to our heart’s content. However, tab bar controllers can only be used once in a project, as the top level controller. So embedding more tab bar controllers does not work.

This is most of waht you need to know to work with basic tab bar controllers. For more information on sharing between the controllers and a more extensive coding example, see Passing Data in Tab Bar controllers.

Basic Auto Layout: A Practical View for Beginners

Note: When I originally posted the Basic Auto Layout video on YouTube, I recorded it live and did not make a script I could post underneath it. This post makes the same UI as the video, but with a few differences in depth of material and process to illustrate how to handle autolayout errors and a few other auto layout subtleties. I will produce a video on this probably in early February. This will be part of the Swift UI book I am writing, but may also become part of my second book on UI design in iOS.

Why Auto Layout?

For most of Xcode’s existence, storyboards were separate for iPads and iPhones. Even among devices, there was a lot of extra work necessary to use the same app in landscape and portrait. With iOS 8 and new phone sizes, this has become a bit more of a problem. We could design a different storyboard for every size and orientation, but that would be an excessive amount of work. Every new version of the phone or tablet would need to be different. If you hear about device fragmentation this is what people are talking about: different devices need different layouts because their screens are different sizes. It’s not just mobile devices that have this problem. Any window for a web page might be a different size. The web page needs to change to handle those differences.
Over that last few years, there are many solutions to adaptive user interfaces, which are interfaces that adapt their size and shape automatically to the device or window they happen to be in. Apple’s solution to this problem is auto layout, which lets the system do the hard work. Using relations between views we describe how to layout the user interface.
In iOS 8, Apple introduced class sizes, a way to describe any device in any orientation. While this removes device fragmentation, class sizes rely heavily on auto layout. Up to iOS 8 you could escape auto layout. Apple changed several methods for user interfaces and view controllers, most notably presentViewController, in a way that you need auto layout to use them effectively. In this chapter, we’ll discuss basic auto layout and size classes so it will make sense when we need to use them.

 

Pins and Aligns

If you take a look at Apple’s auto layout documentation, they go on and on about linear equations. This is very confusing and while explaining how it works, it does not get to the functional meat of how to use it. Let’s look at this differently.

We call the relations between views constraints. Basically there are two types of constraints for a view. The first is the size and space between views, usually neighbor views. These we call pins. The second is between two specific views by an attribute of the view. These we call alignment or aligns. Besides aligns and pins, you will need to update and resolve changes to the constraints with resolvers. At the bottom of the storyboard, you will find a few buttons that make your auto layout changes.

buttons for autolayout

Pins

For a pin, you select one object and describe how far way it is from its nearest neighbors. All pin operations are found on the pin button. If you were to select a view and open it, you would see this:

Screenshot 2015-01-05 05.35.10

The top section sets spacing to the nearest neighbor. If there is no neighbor view, auto layout assumes the superview. On the superview while dragging around a subview you will find blue dotted lines, which are layout guides for the margins. Auto layout will usually base its decisions on these layout guides if your nearest neighbor is the superview.
Below the spacing section in the menu, the sections below that let you set a size. You can set a size specifically for the view using the Width and Height selections. For a size based on the sizes of a neighbor, you can use Equal Widths, Equal Heights and Aspect ratio.
At the very bottom is a drop down  selection allowing you to update the view’s frames to match the new constraints. There are time you want to do this and times you do not.

Aligns

Similar to the pin selections is the alignment selections, which you can reach with the align button:

Screenshot 2015-01-05 05.34.40

To use these, you need to select two views, and then set a relationship between them. Note here we align to a common edge or center. The last two selections Horizontal Center in Container and Vertical Center in Container need only one selection, since they will center to the superview. Here too we have a selection to update the frames.

The Resolver

If we do not update the frames immediately, we can update them in the resolver.

Screenshot 2015-01-05 05.36.32

While the selections are the same for each half of the resolver, what they affect is very different. The top applies only to selected views, the bottom to all views. Try to avoid using the bottom half, unless you are sure you have all your constraints in place. Views tend to disappear if you use this and you don’t have all your views set. The only one in the bottom half used often is Clear Constraints, which is the best way to handle out-of-control problems with constraints.

Once you get a constraint set up correctly, a selected view will have blue i-beams describing the constraints.

Screenshot 2015-01-05 06.56.39

Constraint Errors

Once you start working with constraints, you will get a lot of warnings. All errors for constraints start as a warning, though they may become fatal errors at run time. You will need to resolve all these errors. There are three types of errors: misplaced views, missing constraints and conflicting constraints.

Misplaced Views

Misplaced views have the correct constraints but are not in the place they will display at run time. If you select the misplaced view, it will show how far off from the actual location the view is. The storyboard will also show a dotted rectangle giving the correct position. For example this label is a misplaced view.

Screenshot 2015-01-05 06.46.29

To resolve a misplaced view you select the misplaced view, and in the selected view section click Update Frames in the resolver. You can avoid this step by using the Update Frames selection in the pin and align popovers. You may not want to do this immediately since there is another kind of error to get rid of first.

Missing Constraints

A second kind of error is missing constraints. All views using constraints need enough information to determine location and size of a view. In most cases, auto layout can guess at a size if you give enough position information. For example this button is missing constraints:

Screenshot 2015-01-05 06.43.54

This button has a constraint to the label so it has a horizontal position, though misplaced. It needs a vertical position too. To fix these errors, add some more constraints. For the button, you might align to the top of the label, or pin to the top margin.

Conflicting Constraints

The third type of error is the most difficult: too many constraints. For a button, suppose I pin to the top twice: once 50 points from the top margin and once 53 points from the top margin. The view can’t be in two places at the same time. This causes a conflicting constraint error, which shows as red i-beam in the storyboard.

Screenshot 2015-01-05 07.11.20

To correct a conflicting constraint, delete the conflicts until there is only one constraint. If we clicked on the red constraint above that says 50, and then press the Delete key, the constraints will be correct.

Working with Auto Layout

With the above explanation, let’s try to put together a user interface using auto layout. We’ll use three buttons, a label and a text view and make them work properly on any device in both landscape and portrait.

Set Up the Project

Let’s start with a new project. In Xcode hit Command-Shift-N and make a new single view project named MySizePizzaDemo. Use Universal for the device and set Swift for the Language.

Once loaded, Go to the storyboard. On the bottom tool bar you will see the size classes like this:

Screenshot 2015-01-08 06.02.53

Make sure this reads wAny hAny. This is the most generic case, and thus works with everything. Drag onto the storyboard a label with a green background and black text centered. Make the label read Hello Pizza. Then add a button with a red background with white text titled Done. Add two more buttons with a blue background and white lettering. Title one Cheese and the other Pepperoni. Add a text view with the default black text on white background. Set the superview’s background to black to see everything better.

Arrange the buttons so they look like this:

Screenshot 2015-01-05 20.05.06

Center Align the Text Field

To start using constraints, we will align the text field to the center of the superview. Select the text view and then click the alignment button. Check Horizontal Center in Container  and Vertical Center in Container, and select items of new Constraints like this:

Screenshot 2015-01-05 20.13.48

Your results are not very exciting. The text field almost disappears. This is why you might want to wait until you have set all your constraints to update a frame. In this case we have no size, so auto layout assumes a size of 0 height and 0 width. Click the pin button and set the Width to 175 and the height to 175. Again update the frames for Items of New Constraints. Our text field shows up again.

Pinning the Label

For the label, let’s pin everything. Select the label a pin to the top, left and right margin with a value of 0. Set the height to 36pt like this:

Screenshot 2015-01-05 20.29.20

To turn on the i-beam in the menu, click on one of the dotted i-beams. When entering numbers into the fields be sure to press tab after each entry or the value will revert to its previous value. This time everything is set on this one page. Update frames with Items of New Constraints. The storyboard should look like this:

Screenshot 2015-01-06 05.35.19

You might have noticed we didn’t specify a width. That was intentional. We pinned the leading and training edges of the label to the left and right margins, and let auto layout figure out the width for the device it will display on. The width will act as a rubber band – stretching and compressing to the width of the display.

Constraints on the Done Button with Control-Drag

We could set up constraints the same way for the Done button as we did with the label. There is another way to make a constraint which can be helpful. Using control-drag while on the storyboard brings up a modal menu of all possible constraints in this case. Select the Done button. Control-drag straight down from the button until your cursor is over the black of the superview. You get this menu:

Screenshot 2015-01-06 05.28.58

You can click to select one constraint, or shift-click to select more than one constraint. Click Bottom Space to Bottom Layout Guide.

There is a drawback to this way of making constraints. It does not set the values correctly — control-drag just keeps your current values. You need to go to the size inspector to set the values for the constraint. In the right panel on Xcode click the ruler button, which is next to the property inspector.

Screenshot 2015-01-06 05.45.42

About halfway down, you will find the constraint:

Screenshot 2015-01-06 05.41.00

This tells us the constraint has a value of 29, or it is 29 points away from the bottom layout guide. We want it to be 10 points away. Click the Edit button in the constraint, and change the Constant to 10.

Screenshot 2015-01-06 05.41.34

Press Return after you make the change. The Done button will respond with a misplacement error. Since we have not set enough constraints yet, we will wait to update the frame.
Select the Done button if not already selected. Control-drag directly left into the superview. You will get another menu, different than the first. These menus are context sensitive, and give only what applies to the situation.

Screenshot 2015-01-06 05.52.27

Select Leading Space to Container Margin. Now edit the constant to be -16. Usually we set this to the margin which is 16 points from the edge of the screen. In our case we want to start at the edge of the screen, so we use a constraint of -16.

Screenshot 2015-01-06 05.54.21

From the selected Done button, Control-drag up and to the right. You get this menu.

Screenshot 2015-01-06 06.05.24

Diagonal drags will take both directions dragged as their context.By dragging up and to the right we got trailing and top space constraints. We only need a horizontal trailing space this time. Click  Trailing Space to Container Margin. Change the constraint constant to 0 so we are flush with the margin.

Screenshot 2015-01-06 06.08.28

We have all our constraints, but we can see they are misplaced:

Screenshot 2015-01-06 06.10.18

With the Done button still selected, click the resolver menu and in the top part for Selected views, click Update Frames.

Screenshot 2015-01-07 06.45.09

Our Done button now looks right, and we have blue i-beams.

Screenshot 2015-01-06 06.12.42

Pepperoni’s Nearest Neighbor

Select the Pepperoni button. Using the pin menu set the top to 10 the right to 10, and the left to 0. Set the height to 36. Update the frames as well like this:

Screenshot 2015-01-07 06.52.49

We get something we did not expect:

Screenshot 2015-01-06 06.28.59

The pin menu always relates to the nearest neighbor. The Pepperoni button started overlapping the label. Once one view overlaps another, it is no longer a neighbor. The nearest neighbor heading upward is the top margin, so it placed itself 10 points from the top margin, overlapping the label even more. Since we placed one constraint between Cheese and Pepperoni, auto layout guesses at the vertical placement of Cheese.

There are several ways to fix this. One is prevention. If we dragged the Pepperoni button down slightly before pinning,  it would not overlap the button.  Our pin would have worked. Another option is change the constant for the Top Edge to Container Margin to 46 points so we have our button 10 points below the label. I’m not a fan of this. If our label height changes for some reason, we have the same overlap problem again.

The third solution is to make a new constraint between the Pepperoni button and the label. This is where control-drag is the most useful. When you need to make a constraint between two views that are not neighbors use control-drag.
To prevent a conflict, delete the current constraint by going to the size inspect and clicking on the left side of the constraint:

Screenshot 2015-01-06 06.21.18

Press Delete on the keyboard. It disappears. Now select the Pepperoni button. Control-drag from the Pepperoni button into the label. You will see the label highlight. Release the mouse button. The following menu appears.

Screenshot 2015-01-06 06.21.59

Select Vertical Spacing which is the same as pinning to the top. In the size inspector, you’ll see the constraint Top Space to: Hello Pizza!! has a constant of -26. Edit the constraint to have a constant of 10.

Screenshot 2015-01-06 06.22.21

Update the frame if necessary. You may find this change automatically updates.

Aligning The Cheese Button

We have one more button to go. We already have a horizontal alignment, we just need a vertical. We will align the top of the Cheese button to the top of the Pepperoni button. Select the cheese button and then shift select the Pepperoni button. Click the align menu and select Top Edges. Keep the value at 0. Update frames to new constraints like this:

Screenshot 2015-01-06 06.53.25

With that change, we now have satisfied all constraints and have no errors. It still doesn’t look great. We need to make a few more changes.

 Screenshot 2015-01-06 06.57.55

Filling Space with the Text View

The first change is to fill the middle space with the text view. Select the text view. In the resolver, Clear Constraints for selected views. This is the easiest way to avoid conflicting constraints — get rid of all of them. Click the pin menu. Set the bottom to 10, and the left and right to 0. Don’t update the frames.

Screenshot 2015-01-06 07.05.56

We have a slight problem here using pin for all four directions. Directly above the text view is the label. if we pinned the top with 10. It would pin to the label with 10, overlapping the buttons below. We want the text view to pin to the buttons, so we skip that pin and will use a control-drag to set it. But we have no top constraint or a height. Auto layout will guess the height is 0, and the view disappears if we update frames now. This is why we didn’t update views this time.

Control-drag from the text view to the Pepperoni button. Select Vertical Spacing. You will get a blue vertical i-beam. Place your cursor in the beam and it will highlight. Click once on the i-beam. This is another way to edit the constant. You will see in the size inspector only information about this constraint. change the constant to 10 like this:

Screenshot 2015-01-06 07.19.43

Now the constraint shows a misplaced error. Select the text view again and for the selected views update the frames.

Screenshot 2015-01-06 07.23.11

Equal Widths and Equal Heights

The buttons on the top are bit too small. They should be bigger and more consistent in size. Two constraints help with this: Equal Widths and Equal Heights. These two will take the size constraints of one view and use it for other views. To make them work correctly we need one more constraint on the Cheese button. Pin the right side of  Cheese to 0 and update the frames.

Screenshot 2015-01-06 07.28.23

The Cheese button stretches across the superview. Control-drag from the Pepperoni button to the Cheese button. Holding down shift, select both Equal Widths and Equal Heights.

Screenshot 2015-01-06 07.28.45

The two buttons now are the same size.

Screenshot 2015-01-06 07.31.00

I’d like all my buttons to be the same height. I’d also like them a little taller than they are now for easy entry. Let’s add one last constraint between the Pepperoni and the Done button. Since the text view is in the way, control-drag from Pepperoni to the Done button. Select Equal Heights on the menu that shows up. Select the Pepperoni button again. In the size inspector, find the height constraint and change it to 64:

Screenshot 2015-01-06 07.31.41

If necessary, update frames. Your storyboard should look like this:

Screenshot 2015-01-06 07.32.03

Preview Mode

The square story board does not look like any device I’m familiar with. What this will look like on a device we can get by using the simulator, though that requires building and running the simulator.  A faster way during the layout stage is to use the preview mode in the assistant editor.
Click on the assistant editor. At the bottom of the drop down menu that usually shows you will find a Preview selection.

Screenshot 2015-01-07 05.38.17

Select the Main.Storyboard and the current view appears for a iPhone 4 inch.

Screenshot 2015-01-07 05.44.03

At the bottom of each preview is the name of the device. If you float your cursor over the device name, a small icon for rotation appears.

Screenshot 2015-01-07 05.45.53

Click it and the phone rotates. It may be too big for the panel. On a touch pad, pinch to change the scale until you can see the preview

Screenshot 2015-01-07 05.50.41

On the lower left side of the preview, there is a + button to add more devices to your preview. Click the + button

Screenshot 2015-01-06 07.33.21

A list of possible previews appears. You can select any of these you wish. If you want to see both landscape and portrait at the same time, you can select the same device twice and rotate one.

Screenshot 2015-01-07 06.02.23

Usually you’ll want an iPhone and iPad preview, since these may be different. As we’ll learn more in the next sections on class sizes, you can customize for each size class and orientation. It becomes handy to see every change you make.

Screenshot 2015-01-06 07.33.58

If you make a mistake, the preview pane gets too busy, or need to get rid of a preview device for any other reason, click on the name of the device to select it, then press the Delete key on your keyboard to remove the device.

For those using localization, on the bottom right you will find a button you can use to preview in the different localization languages. Click the default language, and a list of languages appear. One interesting selection for testing is the Double Length Pseudo-language, which doubles all your text to give you an idea how an interface will look with a language that uses a lot of characters.

Screenshot 2015-01-07 05.45.24

With these basics, you can lay out most user interfaces. There are more features and ways to use auto layout. We’ll cover some of those in other lessons.

Auto Layout and Size Classes: The Regular Size and Lining up Buttons Evenly

In the conclusion of our series on auto layout, we’ll discuss the regular size for iPads and one side of the iPhone 6 plus. We’ll make a line of evenly spaced buttons using auto layout, first for the iPad, then again for the iPhone 6 plus in landscape with its odd regular width, compact height size.

Transcript

Hello, welcome to our final installment in the beginning auto layout videos. I’m Steve from MakeAppPie.com

With size classes we’ve discussed there are three classes: Compact, Any and Regular.

We’ve already discussed most iPhones have compact sizes, and in the previous lessons set up a special arrangement in compact height for landscape with buttons on the side.

This lesson will be on the regular class. In its default settings, an iPad and an iPhone 6 plus in landscape have regular sized sides.

iPads have regular sizes on both sides. The iPhone 6 plus has one regular side and one compact side.

In our demo, we’ll continue working with the layout from the previous videos. We’d like to have side by side buttons just below the label in regular views. We’ll also make the Done button proportionally smaller than the rest of the buttons.

We would like to keep our buttons proportionally sized on different devices. However the actual size of the view changes. There are a few techniques in auto layout we will use to accomplish equally sized buttons.

The key to equally sized buttons is keeping the beginning and end buttons in a specific place. We then add constraints to keep aligned vertically and the same space away from every other button. Next, we make all the buttons the same size and height as the beginning button and specify the width and height as necessary for the beginning button. Our final step will be to make one button proportionally sized smaller than the rest.

Let’s do this for all regular width devices. Change the size class to regular width any height.

If you cannot see it, move the preview over to show the iPad preview.

Our vertical constraints for the text view are currently set to be 10 points from the Cheese button and 10 points from the Done button. Those buttons will be moving and will mess up our text view when moved, so we’ll constrain the top and bottom constraints to the container view’s margins instead.

Control drag the text view to the bottom space and click Bottom space to Bottom Layout Guide to make a new constraint for the bottom view.

We’ll also do the same to the top margin of the text view. Control drag from the text view to the top of the container. Select Top Space to Top Layout Guide.

Often it’s best to clear constrains instead of changing them when making big changes. Clear the constraints on the Done button

Clear the constraints on the cheese button as well.

We will need some space to put the done button. Resize the Cheese button by dragging the right handle over until there is some space for a done button. Don’t worry how much, we will be setting sizes later.

Move the Done button to its new position and resize it to generally fit. Again, we don’t have to be anywhere close to perfect, as the constraints will do that for us. You can use the recommended choices from the guides as they show up.

Control drag to the right and select Trailing Space to Container to anchor this to the right margin.

Once done, control drag from the Done button to the Pepperoni button. Shift select Top, Equal Heights and Equal Widths.

Since the Pepperoni button is already anchored and sized we don’t do anything with it. We now need to set the middle Cheese button. Control drag the Cheese button to the Pepperoni button. Shift select Horizontal Spacing, Top, Equal Heights, Equal Widths.

Now control drag from the cheese to the done button. Shift select Horizontal Spacing, and Top.

Update the frames. We now have three buttons of equal widths aligned.

We want the Done button to be smaller than the other buttons. Select the Done button and then click Edit for Equal Width to Pepperoni. Change the multiplier to 1:3.

And we’re done. It looks good on the iPad.

However the preview in iPhone 6 plus in landscape is a big mess. The regular width, compact height has too many constraints and can’t figure out what to do. Change the size class of the storyboard to regular width, compact height.

Select Done and you will see far too many constraints. This is the point that is best just to get rid of it all.

Select the text view, which also has too many constraints and clear its constraints. Move and resize the text view using the guides.

Let’s do the same for the Done button. Select the Done Button and clear its constraints. Move the Done button over to the right margin aligned with the other buttons.

Now let’s get the Cheese button cleaned up. Select and clear the constraints. Move the cheese button to the center.

To finish our cleanup, clear the constraints on the Pepperoni button. It is in the right position so we don’t have to move it.

Select the text view, and then the pin menu. add i-Beams on the bottom, left and right. Pin the left margin to 0 points, the right margin to 0 points, and the bottom to 20 points. Set the height to 240 points.

Select the Pepperoni button. Pin 10 points to the top,10 to the bottom, 0 to the left margin, and update constraints. Remember this is to the nearest views, so we are 10 from the label and 10 from the text view.

Select the Done button. Pin 10 points from the top 10 points to the bottom, 0 points to the right margin, and again update the constraints.

Select the Cheese button. Pin left 10 points and right 10 points but don’t update its constraints. There are placement errors at the moment but we will deal with them after we set the vertical alignment and size.

Control drag from Cheese to Pepperoni and select Top.

Control drag from Cheese to Pepperoni again. We already have horizontal spacing and top defined. Shift click equal widths equal heights.

Set the size of the done button. Control drag from Done to Pepperoni. Shift click equal widths and equal heights.

Now everything is set up correctly. On the resolve menu, click update all frames.

We still need to make the done button smaller. Like before, select the Done button. In the inspector click the Edit button on Equal Width to Pepperoni. Change the multiplier there to 1:3.

Going over to the preview pane, we see the iPhone 6 plus is now set up correctly.

We’ve now completed the size class and auto layout of this app’s storyboard. a general lesson to remember is to start with width any, height: any and work your way to more detailed size classes if you need to make changes.

Thank you for watching this short series on beginning auto layout and size classes. For more cool stuff on iOS app development head over to makeAppPie.com.