Kinderswift 8 Challenge Answers

Watch the video for any commentary. Here are two answers. There a lot of possible ones.

Answer 1

func blueColor(blueVal:Int) -> UIColor {
let color = CGFloat(CGFloat(blueVal) / 255.0)
return UIColor(red: 0.0, green: 0.0, blue: color, alpha: 1.0)
}


blueColor(255)
blueColor(23)
blueColor(128)

Answer 2


//necessary code to run the answer
func pizzaArea(z:Double) ->Double {
//area of pizza : pi * z * z = a
    let pi = 3.14159265358
    return pi * z * z
}


func deepDishVolume(diameter:Double,height:Double){
    let radius = diameter * 0.5
    let area = pizzaArea(radius)
    let volume = area * height
    println(radius,area,height)
}

deepDishVolume(13, 2)


Kinderswift 8: Making Your Own Functions

Transcript

In our last lesson we learned about functions. Swift, and most modern programming languages are nothing more than writing groups of your own functions. In this lesson, we will write our own functions.

In our last lesson you may remember this function

UIColor(white: alpha:)

Which made varying colors of gray. Let’s start by making our own custom function like it, but for various shades of red. Make a new playground, and in the playground type this:

func myColorRed(myRed:CGFloat) -> UIColor{
    return UIColor(red:myRed, green: 0.0, blue: 0.0, alpha: 1.0)
}

Let’s explain the parts of a function. Like we started variables with var or constants with let, we start functions with func. This tells Swift we are writing a function. We next give an identifier for the function, which will be its name. Generally, the identifier starts with a lower case letter.

Immediately after the identifier we have a parameter list surrounded by parentheses. If we have more than one parameter, we separate them with commas. Note each parameter is like an explicit assignment with var.


var myRed:CGFloat = 0

Instead of assigning any value though, the function will get a value when we use the function and place a value int he parameter.

We then write an arrow made from a dash and greater than symbol, followed by the type. This tells us the type of the value returned from the function. This function returns a value of type UIColor.

We then have curly braces surrounding some code. This is known as a code block. You will find that we use the curly braces a lot to make code blocks in Swift.

Inside the code block, usually the last line of the code, you will find return and a value. In this case we use the UIColor initializer to return a red color.

Let’s try this. Type these in


myColorRed(1.0)
myColorRed(0.5)
myColorRed(0.86)
myColorRed(0.92)
myColorRed(0.66)

And we get different values of red.

Let’s try a more complicated example. Type this:

func pizzaArea(z:Double) -> Double {

    // area of a pizza: pi * z * z = a
    let pi = 3.14159265358
    return pi * z * z
}

This finds the area of a circular pizza using z as a radius of circle. z is a Double and we return a Double. We set a constant of pi, and then return pi times z squared.

Try this function out.

pizzaArea(3.0)
pizzaArea(6.0)
pizzaArea(12.5)

Most of the time we do not measure a pizza’s radius but it’s diameter. We say 14 inch diameter or 35cm diameter, not a 7 inch or 17.5 cm radius.

Some functions do not return a value, they do something else, such as print the results. There is a special function to print out results to the console, called println. You place a value or values separated by commas in the parameter and print line will print them to the console.

Let’s combine both the diameter problem and an example of a println function into one function. Add this to the playground

func printPizzaArea(diameter:Double){
    let radius:Double = diameter / 2.0
    let area = pizzaArea(radius)
    println (radius,area)
}

You will notice the arrow is missing. If we do not return a value, we do not add it to the function declaration. We do have a parameter diameter of Double.

In the code block, we find the radius by dividing the diameter by two. We find the area by using our already defined area function. Our third line prints the radius and area to the console.

For a fourteen inch pizza we can type this:

printPizzaArea(14.0)

and it works, but we see nothing. You need to open the console click here to open it

frame01

and you will see a new window on the playground with our answer.
frame02

Now try a pizza at 35 cm

printPizzaArea(35.0)

We get an answer. Our answer does not look very user-friendly though. In our next lesson we’ll look at Strings and formatting.

Challenge Work

If you’d like an assignment until next time here’s two things to try:

Make a blueColor function which returns a blue color as a UIColor from an Int value from 1 to 255.

Make a function to calculate the volume of a deep dish pizza and print the radius, area and height to the console. . Use a diameter and height parameter and the area function we already defined. A hint is the volume is the height time the area.

I’ll post the answers in another video

KinderSwift 7: Introduction to Functions

This session we will learn about functions by making colors with UIColor.

Transcript

Welcome to lesson 7 of KinderSwift.

In our last lesson we used this

Double (2) 

to convert a Int into a Double and this

Int (2.5) 

to convert a Double into a Int. Both of these are functions.

Functions take the data within the parentheses and change it into something else.

Most of Swift is made up of using or creating functions. There are math functions such as this one:

sqrt(100.0)

Which calculates the square root of 100 or this that calculates ten to the power of 3

pow(10.0,3.0)

Here we have more than two numbers in the parentheses separated by commas. Each of these is a parameter. A function may have any number of parameters.

Functions are not just for numbers. For example this:

UIColor(white: 0.5, alpha: 1.0)

Is a function with two parameters. Often you will see identifiers for the parameters, in this case white and alpha. This function makes different colors between black and white.

Here is a function with four parameters.

UIColor(red: 1.0, green: 0.8, blue: 0.2, alpha: 1.0)

This function has a range. The parameters can be from 0 to 1.0. We will need to find documentation to tell us this though. Often you can get to the documentation by clicking the mouse button while hitting option while on a keyword. You can get the most information by clicking the Class reference link.

frame07

Functions may have other expressions, even functions or variables inside them. Often colors get described as values of Red green and blue in a range from 0 to 255. We might have a color described by. (255, 90, 00). We need to divide by 255 to get a range of 0 to 1. We can write that like this:

UIColor(red: 255.0/255.0, green: 90.0/255.0, blue: 0, alpha: 1.0)

Parameters do have type. We can guess that the UIColor function has the type Double,but we would be wrong. It has a new type for us CGFloat. CGFloat is a floating point number like Double, but used for computer graphics.

Let’s try a variable. Type this:

var myRed = 255.0/255.0
UIColor(red: myRed, green: 0.8, blue: 0.0, alpha: 1.0)

you get an error.

myRed is the wrong type. It is a Double not a CGFloat. We have to declare it CGFloat to work here. Compilers like Swift are very fussy about this. CGFloat and Double might look the same to us, but not to Swift.

Add a type to myRed,

var myRed:CGFloat = 255.0/255.0

and everything is okay.

How can we tell what type to use? One way is we watch autocomplete type the statement for us: Try it, Type this

UIColor(

We get this:

frame08

You’ll see that the parameters give their type, just like we assigned types with var and let. UIColor uses CGFloats.

You will also notice something else. there are a lot of functions named UIColor, but with very different parameters. Most of these you will never use, but there a few you might. We’ll discuss which ones in a few lessons when we start making user interfaces.

There are so many functions for UIColor because is UIColor is a type. You might have noticed we broke the rule about a lowercase letter for an identifier in a lot of these functions such as Int() or Double(), though sqrt() and pow() are both lowercase.

Ones with capital letters are all special functions called Initializers. They set the initial value of a type. Usually we assign them like this:

var myColor = UIColor(red: 1.0, green: 0.8, blue: 0.2, alpha: 1.0)

We can then use myColor later in our program. Like Int or Double sometime we use them once to cast a type without assigning them.

For example I can cast myBlue which is a Double into a CGFloat if I need to in my UIColor function like this:

var myRed:CGFloat = 255.0/255.0
var myBlue = 200.0/255.0
UIColor(red: myRed, green: 0.8, blue: CGFloat(myBlue), alpha: 1.0)

Another name for a type is a Class. While there really is no difference between a class and a Type in Swift, the general rule is classes are more complex types. UIColor is a class which has its own functions and variables. Classes will be our focus for many of our upcoming lessons, but to get your feet wet, I’ll introduce another type of function: A class method.

UIColor has a lot of class methods, many without parameters. Instead it has a blank parentheses pair. You use class methods by stating its type then a dot, then the function. for example there is this:

UIColor.blackColor()

and this

UIColor.greenColor()

There are many more of these. Before the next lesson play around with some of the UIColor Class methods and the Red:green:blue:alpha: initializer. You can scroll for them in autocomplete or you can use this list:

The Apple System Colors with a color wheel of RGB primary and secondaries.
The Apple System Colors with a color wheel of RGB primary and secondaries.

Next time we’ll make our own functions.

KinderSwift 6: Types and Casting

In this lesson we cover how to explicitly type an identifier and how to use casting to force its type.

Transcript

Welcome back to kinderswift. episode 6. In our last lesson, we left off with this not working:

//can't mix types:
//doubleResult = myDouble + myInteger

Swift does not let you mix types. This lesson we will learn a little more about types and then how we can get this to work.

We already saw how to declare a double and an integer automatically. We call this implicit typing. In implicit typing, Swift guesses at the type.
so when we type:

var myInteger  = 0

the lack of a decimal point makes Swift guess this is an integer. Similarly

var myDouble = 0.0

the decimal point makes Swift guess that myDouble is type Double. We can also explicitly declare

var myInteger:Int = 5
var myDouble:Double = 5

You will see that Swift accepts both. myInteger is 5 and myDouble is 5.0 , even though we left off the decimal point myDouble is a Double. The difference is after the identifier we added a colon, then a type.
frame2
We know two types so far: Int for integers and Double for doubles. The colon forces Swift to make the identifier that type without guessing.

I can force a Int 5 to be a Double 5.0. Can I declare a Double as an Int? Try this:

var myOtherInteger:Int = 5.0

We get an error. Erase the decimal point and everything is fine. 

var myOtherInteger:Int = 5

No, we cannot assign a Double to an Int.

So for a little test what would this statement do?

myDouble = 3.5
myInteger = myDouble

Try it. type it in.

If you guessed we would get an error assigning a double to an integer, you are correct.
since you know that, you can be pretty certain this will also have an error:

myInteger = 4
myDouble = myInteger

What if you did want to assign integers to doubles and vice versa. What if you needed to add an integer to a double? There is a way called type casting. We take the value and force it to be a certain type. We do this by giving the type and then enclosing the value in parentheses
frame 3
comment out the error lines using // type this:

Int(4.5)
Double(3)

We see in the results we get a value of 4 and a value of 3.0. Int casting will cut off the part after the decimal point, Double just adds one. We can use casting on variables too. Uncomment the lines we just commented. Now change them to:

myDouble = Double(myInteger)

and

myInteger = Int(myDouble)

Now they work. Now we can fix our problem from before.

var doubleResult = myDouble + myInteger

How would you fix this?

We want a result of Double. We have a Double and an Int in the equation. Most likely we will change myInteger to Double like this.

var doubleResult = myDouble + Double(myInteger)

The way we cast Int() and Double() uses something called functions. In our next lesson we’ll discuss using functions a little bit more — including a few colorful ones.

Swift Swift: Using the UIImagePickerController for a Camera and Photo Library.

[Updated to Swift 2.0/iOS9 09/29/2015 SJL]

Screenshot 2014-12-04 07.15.31Almost every iPhone and iPad now has a camera. Many people want to use a camera in their apps for various reasons. While you may not be building the next Instagram or Twitter, there are many places where photo documentation comes in handy.

There are two ways to use the camera. The more powerful and advanced method is using AVFoundation, but it is also a very complicated way to get a photo out of the camera.

The simpler way is the UIImagePicker. This is a quick way as Swift has simplified much of the code for it.  It is also the best way to fetch photos from the photo album. In this lesson, we’ll set up a basic camera and library app. In upcoming posts we’ll add a few embellishments to it that will make for a more effective camera.

Set Up The Layout

I’m going to set this up universally.  We’ll be talking about some of the issues with camera on both iPad and iPhone.  As a universal app we will be using auto layout. If you want a brief introduction to auto layout go over and Take a look at my book Practial Autolayout. You won’t need it for this lesson, but it may make what I do a little more understandable.

Make a new project SwiftPizzaCam with a single view and using Swift. As already mentioned, make the device Universal.

Go to the storyboard and check that the size classes say w:any h:any. Change the background color to black.

If you are not familiar with the auto layout icons, here is a guide to help you as we go through setting up the app.

autolayout buttons

We will put a photo into an UIImageView when we first  use the image.  Right click and save the image below:

pizza

Click on Assets.Xcassets and drag the pizza file into the assets folder. Go back to the story board and select the clip icon.  You will find the pizza media there.

Screenshot 2014-12-03 08.47.26

Drag out the pizza to the view and drop it into the view controller. Click the pin button. Click on all the i-beams, then change numbers like the photo below:

Screenshot 2014-12-03 05.19.18

Be sure to press tab after you type in any number in this popover. It has an annoying habit of forgetting them if you don’t. Also make sure you select Update Frames: Items of New Constraints towards the bottom. If you don’t, you will need to click the resolver and select Update Frame from the upper part of the popup. In the properties change the View Mode to AspectFit to properly size the photo.

Screenshot 2014-12-03 08.48.32

Now drag out a label onto the storyboard. Set the background property to a gray color with a 65% alpha.  Center the label. Change the text of the label to read Pizza Cam!!!.  Select the label and then pin the top left and right sides, but not the bottom, like this:

Screenshot 2014-12-03 05.17.44

Make  sure you select Update Frames: Items of New Constraints towards the bottom before adding the three constraints.

Drag out  a toolbar and place toward the bottom of the view. Pin it to the bottom, left and right like this, again updating the frames:

Screenshot 2014-12-03 05.18.23

Add a bar button item and a flexible space bar item to the toolbar. In one of the two bar buttons label it Photo and the other Library. Your tool bar and layout should look like this:

Screenshot 2014-12-03 14.59.18

If you did everything correctly, you should have no auto layout warnings. If you do, go to the resolver and click Update Frames on the bottom half of the popover. If things get messier after doing this, clear the constraints on the bottom of the resolver, and pin everything again.

Wire Up the Outlets

Your next step is to wire up all the outlets and actions. Control-drag from the image view and make an outlet called myImageView. Control drag from the Library button and make an action called photoFromLibrary with a sender of type UIBarButtonItem. This is important for stuff we will do later. Do this again, but with the Photo button and named shootPhoto. Again, make the sender UIBarButtonItem.
You can clean up the code a bit if you like. When done you should have something like this:

import UIKit

class ViewController: UIViewController{
    @IBOutlet weak var myImageView: UIImageView!

    @IBAction func shootPhoto(sender: UIBarButtonItem){
}
    @IBAction func photofromLibrary(sender: UIBarButtonItem) {
   }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    }
}

Add the UIImagePickerController and Delegate

The star of our show the UIImagePickerController is missing. We do that programmatically. Close the assistant editor, and open ViewController.swift. Add the following line under the outlet for myImageView:

let picker = UIImagePickerController()

The UIImagePicker does much of its works from a delegate. Add the following to the class description:

class ViewController: UIViewController, 
    UIImagePickerControllerDelegate,
    UINavigationControllerDelegate {

We actually have two delegates: UIImagePickerControllerDelegate and UINavigationControllerDelegate. The UINavigationControllerDelegate is required but we do nothing with it. In the viewDidLoad, add the following:

 override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        picker.delegate = self

    }

We have wired up the delegate. Unlike other delegates, there is no required methods. However, this will not work without implementing two methods. At the bottom of the class, add the following:

//MARK: Delegates
func imagePickerController(
    picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [String : AnyObject]) 
{

}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {

}

These two methods handle our selections in the library and camera. We can either handle the cancel case with imagePickerControllerDidCancel or handle media with didFinishPickingMediaWithInfo

Getting a Photo from the Library

The UIImagePickerController is a view controller that gets presented modally. When we select or cancel the picker, it runs the delegate, where we handle the case and dismiss the modal. Let’s implement the photo library first, then the delegates. Add the following code to the photoFromLibrary method:

@IBAction func photofromLibrary(sender: UIBarButtonItem) {
picker.allowsEditing = false //2
picker.sourceType = .PhotoLibrary //3
presentViewController(picker, animated: true, completion: nil)//4
}

To get to the photo picker, it is three lines of code. We already initialized picker. In line two, we tell the picker we want a whole picture, not an edited version. In line three we set the source type to the photo library, and line four we use presentViewController to present the picker in a default full screen modal.

If you build and run, you would be able to press the photoFromLibrary method and then get stuck in the library. We need delegates to get out of the library. First let’s add the code for the cancel delegate:

func imagePickerControllerDidCancel(picker: UIImagePickerController) {
    dismissViewControllerAnimated(true, completion: nil)
}

This does nothing special: it dismisses the modal controller. If we do pick a photo, we want to do something with the photo. Add the following code to the didFinishPickingMediaWithInfo delegate method:

func imagePickerController(
    picker: UIImagePickerController, 
    didFinishPickingMediaWithInfo info: [String : AnyObject]) 
{
    let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
    myImageView.contentMode = .ScaleAspectFit //3
    myImageView.image = chosenImage //4
    dismissViewControllerAnimated(true, completion: nil) //5
}

One of the parameters of this method is info. It has a dictionary of various information about the selected media, including metadata,  a user edited image if the .allowsEditing property is true, and a NSURL location of the image. For our camera app, the important key is the UIImagePickerControllerOriginalImage. We take that key and put the image into a variable. We could make this a constant, but there is some future iterations of this project that will need this as a variable.

Camera images are usually bigger than a UIImageView on a device. To shrink them quickly to a visible size, the best way is to set the .contentView property of our UIImageView to .ScaleAspectFit as we do in line 3.

Running as an iPhone and iPad app: Using Popovers

Run in the simulator as a iPhone 5s. You should get a screen like this:

Screenshot 2014-12-04 06.04.04

Tap the library bar button. You will get an alert:

Screenshot 2014-12-04 06.04.15

Apple requires any use of the camera, the photo library or any personal information for that matter asks the user to agree sharing information with the app on the first use. For the UIImagePicker, this is included in your first run of the app.  Tap OK.  We get our Image picker,

Screenshot 2014-12-04 06.04.28Screenshot 2014-12-04 06.04.41

When we tap a photo, it appears on the app.

Screenshot 2014-12-04 06.36.23

Stop the app and run as an iPad 2. After answering OK to the library privacy question you get this:

Screenshot 2014-12-04 06.11.38

Which looks fine, except Apple doesn’t like it. They want you to use a  popover.  If you present this as a modal using presentViewController in anything before iOS 8 , you  will get an exception and crash the app — Apple forces you to use a popover. All that changed in iOS 8 when modals and popovers merged into presentViewController.  The class documentation still notes that popovers are required for accessing the photo library on iPads when using the newly deprecated way of presenting a popover. I cannot find the correct way in the Human Interface Guide, but I think it is still good style to use a popover.   Fortunately in iOS 8, it is very easy to get the popover to work. Change this in photoFromLibrary

presentViewController(picker,
    animated: true,
    completion: nil)//4

to this:

picker.modalPresentationStyle = .Popover
presentViewController(picker,
     animated: true, completion: nil)//4
picker.popoverPresentationController?.barButtonItem = sender

Line 1 selects a presentation style of a popover. We then present the popover, and set the reference point for the popover to the bar button item. As I mentioned in another post popovers need a reference rectangle to pop up from. In this case, we can use the UIBarButtonItem which happens to be sender . This is why it was so important to use UIBarButtonItem as the sender type.

Build and run with the iPad 2 simulator. Now we have a popover to pick a photo.

Screenshot 2014-12-04 06.20.00 Screenshot 2014-12-04 06.20.28

I don’t know if using a full Screen modal will cause an app to be rejected, but since it is not hard to add, and presentViewController will present the right controller for the space available, this is probably a good idea — especially since it solves lots of problems with the iPhone 6 Plus models and multitasking, which can use both popovers and modals depending on circumstances.

Screenshot 2014-12-04 07.15.31

We save ourselves from hours of device fragmentation work this way.

Adding a Camera: Where Simulators Fear to Tread.

Basic Camera code is almost the same as adding a photo library. Change the shootPhoto code to this:

@IBAction func shootPhoto(sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.Camera
picker.cameraCaptureMode = .Photo
picker.modalPresentationStyle = .FullScreen
presentViewController(picker,
    animated: true, 
    completion: nil)
}

We changed the sourceType property to .Camera and specified the cameraCaptureMode property to .Photo. Camera, unlike the photo library, is required to be full screen, so we don’t make it a popover, but explictly a .FullScreen.

If you build and run this in the simulator, you will crash.

SwiftPizzaCam[1649:42600] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Source type 1 not available'

In order to test and use camera code you have to use a real connected device. I connected my iPad mini and ran the code. When I pressed the photo button, I again get the message about allowing access.

Photo Dec 04, 7 29 44 AM

Tapping OK, I get the camera:

Photo Dec 04, 7 30 07 AM

Take a picture, and the app asks me if I want to keep it.

Photo Dec 04, 7 30 35 AM

The app returns with my photo.

Photo Dec 04, 7 30 22 AM

This all works, but we really want to prevent that crash. Since we are using iOS 9, we don’t have to code so much as earlier versions due to a truth about our hardware: All the hardware that anything above iOS 8 works with has a rear camera. We just have to look for a rear camera. One way to do that is with a UIImagePickerController class method availableCaptureModesForCameraDevice. If nil, there is no hardware. Change the method to this:

@IBAction func shootPhoto(sender: UIBarButtonItem) {
    if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
        picker.allowsEditing = false
        picker.sourceType = UIImagePickerControllerSourceType.Camera
        picker.cameraCaptureMode = .Photo
        presentViewController(picker, animated: true, completion: nil)
        } else {
            noCamera()
        }
}

Line 2 checks if there are any devices. If there is, run the camera. If not, execute our handler code noCamera. For that handler we’ll add an alert like this, using UIAlertController:

func noCamera(){
    let alertVC = UIAlertController(
        title: "No Camera",
        message: "Sorry, this device has no camera",
        preferredStyle: .Alert)
    let okAction = UIAlertAction(
        title: "OK",
        style:.Default,
        handler: nil)
    alertVC.addAction(okAction)
    presentViewController(alertVC,
        animated: true,
        completion: nil)
}

Line 2 makes an alert with the proper message. We add an OK action button in lines 3 and 4, then present the alert as a modal in line 5. With this code, if you run in the simulator, you get this when you attempt to take a picture:

Screenshot 2014-12-04 09.05.26 copy

The Basics, but Wait! There’s more!

Basic UIImagePickerController is relatively easy to implement, but there are a lot of issues it leaves hanging:

  • Hitting no for privacy settings for  accessing the camera or library
  • Dealing with more than one popover
  • Customizing and adding more controls for the camera
  • Adding and playing video
  • Using  and storing pictures
  • Using a UIScrollView to zoom and scroll around a picture.
  • Getting rid of  the memory warnings
  • Wanting more power over my camera controls
  • Sharing pictures with my friends

Many of these could be questions that can be answered in context with the camera app, or outside of that context. In other lessons I’ll be answering them both ways. We’ll have posts about individual concepts, like a post on  UIScrollView and then a post on how to add it to the camera app.

The Whole Code

//
//  ViewController.swift
//  SwiftPizzaCam
//
//  Created by Steven Lipton on 12/3/14.
//  Copyright (c) 2014 Steven Lipton. All rights reserved.
//
// Basic a camera app that takes pictures and grabs them for a background from the photo library

import UIKit

class ViewController: UIViewController,
    UIImagePickerControllerDelegate,
    UINavigationControllerDelegate {

    @IBOutlet weak var myImageView: UIImageView!
    let picker = UIImagePickerController()   //our controller.
                                             //Memory will be conserved a bit if you place this in the actions.
                                            // I did this to make code a bit more streamlined

    //MARK: - Methods
// An alert method using the new iOS 8 UIAlertController instead of the deprecated UIAlertview
// make the alert with the preferredstyle .Alert, make necessary actions, and then add the actions.
// add to the handler a closure if you want the action to do anything. 

    func noCamera(){
        let alertVC = UIAlertController(
            title: "No Camera",
            message: "Sorry, this device has no camera",
            preferredStyle: .Alert)
        let okAction = UIAlertAction(
            title: "OK",
            style:.Default,
            handler: nil)
        alertVC.addAction(okAction)
        presentViewController(
            alertVC,
            animated: true,
            completion: nil)
    }

    //MARK: - Actions
//get a photo from the library. We present as a popover on iPad, and fullscreen on smaller devices.
    @IBAction func photoFromLibrary(sender: UIBarButtonItem) {
        picker.allowsEditing = false //2
        picker.sourceType = .PhotoLibrary //3
        picker.modalPresentationStyle = .Popover
        presentViewController(picker, 
            animated: true, 
            completion: nil)//4
        picker.popoverPresentationController?.barButtonItem = sender
    }

//take a picture, check if we have a camera first.
    @IBAction func shootPhoto(sender: UIBarButtonItem) {
        if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
        picker.allowsEditing = false
        picker.sourceType = UIImagePickerControllerSourceType.Camera
        picker.cameraCaptureMode = .Photo
        picker.modalPresentationStyle = .FullScreen
        presentViewController(picker,
            animated: true,
            completion: nil)
        } else {
            noCamera()
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        picker.delegate = self   //the required delegate to get a photo back to the app.
    }
    //MARK: - Delegates
//What to do when the picker returns with a photo
    func imagePickerController(
        picker: UIImagePickerController, 
        didFinishPickingMediaWithInfo info: [String : AnyObject]) 
    {
        var chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
        myImageView.contentMode = .ScaleAspectFit //3
        myImageView.image = chosenImage //4
        dismissViewControllerAnimated(true, completion: nil) //5
    }
//What to do if the image picker cancels.
    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        dismissViewControllerAnimated(true,
           completion: nil)
    }
}

Proportional Sizes in Autolayout

Transcript

Welcome to this quick lesson on auto layout and proportional spacing of elements.

In the previous videos, we used equal widths to set the spacing for  various elements in auto layout.

But what if you want the sizes to be different? For example, what if in the app we are working with the buttons need to be bigger than the text area or the text area needed to be  bigger than the buttons?
Size classes Keynote 2.003

There is a way to do this. One of the properties of a constraint we have yet to play with is the multiplier. By changing the multiplier for equal widths, we get a proportional width constraint which takes the multiplier as a ratio of the two elements in the constraint.
Size classes Keynote 2.005

Let’s try this out. Select the text view in the project. and then click Edit in the constraint in the inspector. You’ll find the multiplier text box there.

Change the multiplier to 1:3 and you will see the button be three times as large as the text view.
frame 001 112514

Now try 3:1. You will  see the text view is now three times as big as a the buttons.
frame 002 112514
For a good look in this app, lets have the buttons be one and a half times as big as the text view.  We can type that in by 1.5:1.
frame003 112514
That looks good.

We can also use 1.53:2 or 3/2 to get the same result.

As we’ll see in the next lesson in this series,  This will let us make a small done button on a line of buttons for our iPad layout.

Swift Swift: Using Auto Layout with Size Classes

Last week we looked at the basics of auto layout, this week, we learn

  • Diagonal Control Drag
  • Using the layout error  panel for misplaced layouts
  • Introduce Size Classes
  • Make a different layout for iPhone in portrait with Size Classes

Transcript

Hello, I’m Steve from MakeAppPie.com. In this video we are going to learn some more about Auto Layout and how to use Xcode’s new size classes feature. We’ll start with the completed project from the last video, so you might want to check that out first:

In the last project we made a universal app like this:

Screenshot 2014-11-12 06.24.40

It works the same for iPhone and iPad. It also works the same for each device in both landscape and portrait. Size classes let us customize certain devices or orientations for a different layout than this generic layout.

If you click the width and height size class you will get a popup with a bunch of squares on it. This allows you to set the size class you want to work with.

Size classes Keynote photos.002

There are three sizes for size classes: compact, any, and regular. Any is the generic size that works with anything. Our current layout, as we can see on the bottom the story board is width:any height:any. This layout is for all cases.

Size classes Keynote photos.003

iPhones and the iPod touch are the compact size in both landscape and portrait, with one exception.

Size classes Keynote photos.004

For both width and height, iPad is the regular size. The width in landscape is regular for an iPhone 6+.

Screenshot 2014-11-14 10.16.41

In our application, we will change the location of the three buttons from above and below the text file to left side of the text field for the compact iPhones in landscape, and leave them the way they are in portrait. For the iPad and iPhone 6, we’ll move all three buttons to the top of the screen in our next video.

Screenshot 2014-11-12 05.58.45

In the storyboard, click the width:any height:any button on the bottom of the storyboard. Move the square to any width, compact height for a iPhone in landscape.

Set up Xcode with the preview mode to have the phones in landscape so we can check them as we go through the steps. if you have the file browser open, you may want to close it to give yourself more room. Keep the document outline open.

To start let’s move the text view to the new location. Select the text view in the document outline. Select clear constraints in the constraints resolver. Drag the left handle so the view is less wide than the cheese button. We want to have a relationship to the pizza label, not the cheese button, so we can’t use the pin menu. Control drag from the text view to the label and release. select Vertical Spacing.

Screenshot 2014-11-14 10.18.12

Since we will be moving the done button, we want a relationship with the bottom of the container, not the button. We also want a relationship with the right margin. We can do both at once with a diagonal drag. Control-drag from the text view to the bottom right corner. Xcode give us both trailing and bottom constraints. Shift click the Bottom space to container margin and Trailing space to container margin, then press return. Xcode adds both constraints.

Screenshot 2014-11-14 10.21.28

As the warning indicates, we still have one more constraint to go, but we will get to that in a minute. Clear the constraints on the Cheese button. Move it under the pepperoni button.

Select pin and pin the cheese to the pepperoni 10 points away and the left margin 0 points away. Update the frames to the new constraints.

As you can see in the preview window, the buttons are now too small. Let’s fix the height first. Control drag from Cheese to Pepperoni and shift-select equal widths and equal heights. Remember pepperoni has an explicit width of 64, so that will make both 64 points high.

We get several layout error, but we can see in the preview that they are now the right width. Note on the preview that the text view has disappeared. That’s because we still didn’t set its width, which we’ll do as an equal width to the buttons, and have a space between them of 10 points.

Control drag from the pepperoni button to the text view. Shift select Horizontal spacing and equal widths, then press return. We get more errors. Click on the horizontal spacing constraint we just made, and in the inspector change the constant to 10 and press tab.

The preview shows we have the correct horizontal spacing but the storyboard shows errors. You’ll notice a small error indicator in the upper right corner of the inspector. If you click it, you will see your errors. All are misplaced views.

Select cheese on the storyboard, and click update frames for the selection. That fixes that.

You can also resolve misplaced views in the error panel. Select the warning icon for pepperoni and a pop up lets you update the frame. Select Update Frame and click Fix Misplacement. Now pepperoni is correct.

Screenshot 2014-11-14 10.23.16

Go back to the document outline and select the text view. Scroll to the constraints and change the top space to 10 points and the bottom space to 20. Select Text View in the outline and in the resolver Update selected frames

We need to lay out the done button next, which is now under the text view.  In the outline, select the Done button. Clear its constraints.

In the done button. we won’t bleed off the edge this time. We will instead align it with the other buttons. Pin the done button to the left margin with 0 and the bottom to 20. Update the frame.

You can control drag from the outline too, for cases where you can’t see you frame. Control drag from the done button in the outline to the text view. select horizontal spacing. Now in the inspector change trailing space to text view to 10.

Lets set the size of the button. Control drag from the done button to the pepperoni button. Select equal widths and equal heights. We get a constraint error which is just a misplaced view. Click the icon and fix the misplacement.

We’ve completed the re-arrangement for the iPhone and iPod touch. In the preview, rotate the device, and you will see that it only arranges itself like this in landscape.

Go over to the iPad, and it ignores this.

The iPhone 6 plus is not happy though. This is okay for now, because in out next lesson, we are going to make a different layout for regular width any height layouts.

Size classes Keynote photos.007