# Lab 3 - Auto Layout ## Overview This week we will be covering Auto Layout. This is a super important topic as we need out apps to work with a variety of screen sizes and orientations. This is a topic that will follow you thought your mobile career. ### Required User Stories We want our app to run on many devices so we need to make our UI adaptive in two ways. :::info - Orientation - Screen Size ::: We will do this by adding constraints and SatckViews to our main storyboard. ## Intro to AutoLayout Auto Layout allows you to specify how your app looks based on the view and the orientation. Many of you have played around with this and it can be very intimidating. If you have done web development you can think of Auto Layout as a responsive design. Or if you have done Android development you will most likely have been exposed to Auto Layout because of the many devices. The goal of AutoLayout is to make the app look as intended depending on the size and orientation. Today we have many different iPhone iPad and watch sizes and we need to account for them. :::warning :heavy_check_mark: Check it out :exclamation: [Apple Documentation](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html) [Outside Resource](https://www.twilio.com/blog/2018/05/xcode-auto-layout-swift-ios.html) [Outside Resource](https://www.appcoda.com/learnswift/auto-layout-intro.html) [Outside Video Resource](https://www.youtube.com/watch?v=27TFuaOpUsE&list=PL23Revp-82LI-MTPyLtvzTCDl-vJKwjlU) ::: ### How it works If you have taken algorithm classes then you may have heard of [***dynamic programming***](https://en.wikipedia.org/wiki/Dynamic_programming). If here is a quick overview, Dynamic Programming is trying to find the best solution given a list of constraints. Auto Layout uses this idea and tries to estimate the best placement of views based on the orientation and size of the device given the constraints we provide. ## Implementing AutoLayout ### There are 4 ways to use AutoLayout **1 - Code** :face_with_head_bandage: This is a great way to handle AutoLayout if you are working in a large team or want full control of your views. Although this is more difficult to master it's worth taking a look into because it is still used in some large projects to avoid merge conflicts. To do this we have a few options: :::info - Creating instances of constraints(NSLayoutConstraint) and adding them to the view - Visual Format Code which is a micro language that is inserted into strings and passed into views - Creating constraints using the Interface Builder *NOTE: We will use this to make minor changes* ::: ```Swift // Get the superview's layout let margins = view.layoutMarginsGuide NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true func addConstraints() { //Collect Views to apply VFL let buttonsDictionary = ["button1": flagButton1, "button2": flagButton2, "button3": flagButton3] //Metrics establish Fixed Constants let metrics = ["topSpacing": 80, "bottomSpacing": 20, "buttonHeight": 20, "buttonSpacing": 20] //Note that priorities can be set using @. 1000 for Required. < 100 for Optional. Example: @999 //Horizontal constraints for buttonName in buttonsDictionary.keys { view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[\(buttonName)]-|", options: .allZeros, metrics: nil, views: buttonsDictionary)) } //Vertical constraints view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(==topSpacing)-[button1(>=buttonHeight@997)]-(==buttonSpacing@999)-[button2(==button1)]-(==buttonSpacing@999)-[button3(==button1)]-(>=bottomSpacing@998)-|", options: .allZeros, metrics: metrics, views: buttonsDictionary)) } ``` :::warning [Apple constraint example](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ProgrammaticallyCreatingConstraints.html) ::: **2 - Xib Files** This was the standard before storyboards. They are much simpler to work with than storyboards because they only have one scene. It is good to read up and get some practice with Xib files because some apps still use them and are easy to use when reusing a view controller. :::warning [Outside Resource: What is a XIB?](https://medium.com/@tjcarney89/whats-a-xib-and-why-would-i-ever-use-one-58d608cd5e9b) [Outside Resource: Creating a XIB](https://medium.com/better-programming/swift-3-creating-a-custom-view-from-a-xib-ecdfe5b3a960) ::: **3 - Constraints Through StoryBoards** :face_with_monocle: This is the current standard and what you may have been using in our class we will use this method along with StackViews. They allow us to layout multiple views and scenes. Because storyboards are static meaning they don't change with the screen we need to add constraints to elements so they can be orientated correctly. :::warning [Apple Anatomy of a Constraint](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/AnatomyofaConstraint.html) [Apple Constraints in Interface Builder](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html) ::: <img src="https://i.imgur.com/FIwF8I8.png"/> <br><br> **4 - Stack Views** :+1: :yum: This is the easiest way to implement AutoLayout. We will use this method first and then use the Interface Builder to help us get the look we want. **What is a StackView?** A StackView is a view that contains sub-views, and they allow us to all the views it contains. A StackView can organize views vertically and horizontally. :::info :bulb: *Tips:* - Use StackViews first then add constraints later - Work from the inside out. Focus on one area and work your way out. ::: **Properties of Views:** :::warning [**Outside Resource: View Properties**](https://medium.com/@abhimuralidharan/ios-content-hugging-and--compression-resistance-priorities-476fb5828ef) ::: - **Intrinsic Content Size:** The default size of the content displayed. Labels with different text lengths have different sizes - **Compression:** Determines how the view will behave and how likely it is to change when the display size decreases. - **Hugging:** Determines how the view resists being changed :::info [Outside Resource Hugging](https://medium.com/@abhimuralidharan/ios-content-hugging-and-content-compression-resistance-priorities-476fb5828ef) ::: **Properties of StackViews:** :::warning [**Apple StackView Properties**](https://developer.apple.com/documentation/uikit/uistackview) ::: - **Axis:** This Property allows the StackView to arrange the views vertically or horizontally. The default is horizontal, but this can be changed based on our needs. This property can be animated and changed in runtime. - **Spacing** Determines the spacing between the horizontal views this can be a positive or negative value. *Note:* Spacing takes priority over the intrinsic content size, meaning this it will shrink the view before the spacing. - **Distribution:** This allows you to control how the views behave on the axis - [***Learn The different properties of Distribution***](https://developer.apple.com/documentation/uikit/uistackview/distribution) - **ALignment** Determines how the vies will take up vertical space. ## Project Setup - The checkpoints below should be implemented using the Pair Programming method - Use your Week 2 Yelpy project as a starting point. - You'll be using the same GitHub repository you've used for each iteration of your Yelpy App. Here is a project starter if you don't have the lab from last week :::success **@[[assets/yelpy_starter_3.zip]]** ::: ## Implementing Auto Layout <img src="https://i.imgur.com/M5fq70K.png" height=400/> <br> ### Step 1: How do you want it to look? :thinking_face: Determine the UI and layout of the subviews - How do you want the layout to look? - How do you want the app to look with different screen sizes? - What orientation do you want the app to be in? <img src="https://i.imgur.com/GRPnh0f.png" height=400/> ### Step 2: Configure the StackView Place the items into the StackView. It is best to start small work from then inside out. Place the StarsImage and the ReviewsLabel into a StackView by command clicking each element and then going to the embed in button and select stack view. :::info ***Note:*** Based on where the items are placed on the storyboard Xcode will estimate whether to put them into a vertical or horizontal StackView. You can always change it later. ::: ![Constraints](https://i.imgur.com/Ud6PRqv.gif) Description: Here is a gif showing how you add elements into a StackView <img src="https://imgur.com/ycsgpyq.png" width="200" /> <br> <br> Description: See how the Reviews label and the Stars Image changed size :::info ***Note***: Why did this change our item sizes?* They were changed back to there Intrinsic Content Size and the were distributed to the available empty space. We can fix this later. ::: ### Step 3: Continue Using StackViews when possible Now we can build out and embed all of our elements into StackViews. - Add more StackViews one for the - One containing the Resturant Image - One containing the Name Label, Category Label, and Phone label - One containing both StackViews <img src="https://i.imgur.com/Pqv6E5i.png"/> ### Step 4: Add constraints: Now we have all of our stack Views we need to add constraints. --- - Remember that we need 4 constraints (2 Horizontal and 2 Vertical) :::warning :bulb:***Note:**** If out item has an intrinsic content size then we only need 2 (1 Horizontal and 1 Vertical) ::: To add a constraint click the item and control drag it. <img src="https://i.imgur.com/i1GtRbs.gif" /> ### Step 5: Making Minor Changes :mag: Play with the stack views and constraints until you have the desired look. Try clicking on the StackView and changing the Axis, Alignment, Distribution, and spacing until you have the look you want. ### Resources :books: This topic can be intimidating and can be frustrating, we recommend that you create a view with a few buttons and labels to get the hang of it. Here are some additional items that can help you. :::warning - [Apple AutoLayout Documentation](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1) - [Apple StackView Documentation](https://developer.apple.com/documentation/uikit/uistackview) - [Apple Constraints Documentation](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html) - [CodePath Guide](https://guides.codepath.com/ios/Auto-Layout-Basics) ::: ### BONUS Try the app on a horizontal view. Figure put what happened to our AutoLayout. :::info It may have something to do with your constraints :thinking_face: :::