36

I know I'm missing something, because this has to be something easy to achieve.

My problem is that I have in my "loading screen" (the one that appears right after the splash) an UIImageView with two different images for 3.5" and 4" size screen. In a certain place of that images, I put one UIActivityIndicator, to tell the user that the app is loading something in the background. That place is not the same for both images, because one of them is obviously higher that the other, so I want to set an autolayout constraint that allows me to put that activity indicator at different heights, depends on if the app is running in an iPhone 5 or not.

Without Autolayout, I'd set the frame.origin.y of the view to 300 (for example), and then in the viewDidLoad method of the ViewController, I'd ask if the app is running in an iPhone 5, so I'd change the value to, for example, 350. I have no idea how to do this using Autolayout and I think it has to be pretty simple.

Daniel
  • 683
  • 1
  • 9
  • 20

5 Answers5

109

You can create an NSLayoutConstraint outlet on your view controller and connect the outlet to the activity indicator's Y constraint in your xib or storyboard. Then, add an updateViewContraints method to your view controller and update the constraint's constant according to the screen size.

connecting constraint to outlet

Here's an example of updateViewConstraints:

- (void)updateViewConstraints {
    [super updateViewConstraints];
    self.activityIndicatorYConstraint.constant =
        [UIScreen mainScreen].bounds.size.height > 480.0f ? 200 : 100;
}

Of course you will want to put in your appropriate values instead of 200 and 100. You might want to define some named constants. Also, don't forget to call [super updateViewConstraints].

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 4
    If you haven't watched the auto layout videos from [WWDC 2012](https://developer.apple.com/videos/wwdc/2012/), you should try to find the time to do so. This is covered, along with lots of other helpful tips. (Search for “auto layout” on that page, not “autolayout”.) – rob mayoff Apr 02 '13 at 08:38
  • 2
    What tool did you use for your awesome GIF? – Klaas Sep 15 '13 at 19:03
  • 11
    I used ScreenFlow to record the screen and to edit and crop the recording. I used Photoshop to turn the movie into a GIF. – rob mayoff Sep 15 '13 at 19:18
  • 1
    @robmayoff - Great explanation indeed, perhaps you have idea how to achieve same result without updating constraints in runtime? It would be great if Interface Builder could show me updated layout when I'm switching between 3.5 and 4 inches form factor. Without that I'm forced to prepare UI for one screen size and use hacks in runtime to adjust view's position to actual screen size. – Darrarski Sep 29 '13 at 22:10
  • Question—what does the f mean in 480.0f? – Mirror318 Dec 23 '13 at 06:50
  • 1
    The `f` suffix makes it a `float` constant instead of a `double` constant. This lets the compiler generate a `float` comparison instead of a `double` comparison, which should be faster on 32-bit iOS devices. – rob mayoff Dec 23 '13 at 15:19
  • Although I upvoted for this answer since it works, it totally defeats the purpose of using the "Auto" Layout. I wonder if there's a way to do it in Interface Builder and not code. – Genki Feb 24 '14 at 19:51
  • @Gomfucius The original question was about positioning an element so it would match an image which differs depending on the device size. Depending on what you want to do, it may be doable entire in your xib or storyboard. Post a question with the details of what you want to do. – rob mayoff Feb 24 '14 at 20:54
  • @robmayoff this is simplet...thanks...but is this possible in storyboard using other features like priorty,multiplier in constraints???How you do in your project..i am really stuck on my project while developing an app for iphone4s and iphone6.... – LC 웃 Aug 11 '15 at 12:57
  • How can I use this method in Swift? I got crash. – ilovecomputer Jun 20 '16 at 10:29
  • You need to post a new question. Be sure to include the Swift code you wrote, and the details of the crash. – rob mayoff Jun 21 '16 at 03:44
  • lack of monospace-font detected – netdigger Feb 16 '17 at 10:50
17

The problem of @Rob answer's is you should do a lot of code for each constraint. So to resolve that, just add ConstraintLayout class to your code and modify constraint constant value for the device that you want in the IB :

enter image description here

//
//  LayoutConstraint.swift
//  MyConstraintLayout
//
//  Created by Hamza Ghazouani on 19/05/2016.
//  Copyright © 2016 Hamza Ghazouani. All rights reserved.
//

import UIKit

@IBDesignable
class LayoutConstraint: NSLayoutConstraint {

    @IBInspectable
    var 3¨5_insh: CGFloat = 0 {
        didSet {
            if UIScreen.main.bounds.maxY == 480 {
                constant = 3¨5_insh
            }
        }
    }

    @IBInspectable
    var 4¨0_insh: CGFloat = 0 {
        didSet {
            if UIScreen.main.bounds.maxY == 568 {
                constant = 4¨0_insh
            }
        }
    }

    @IBInspectable
    var 4¨7_insh: CGFloat = 0 {
        didSet {
            if UIScreen.main.bounds.maxY == 667 {
                constant = 4¨7_insh
            }
        }
    }

    @IBInspectable
    var 5¨5_insh: CGFloat = 0 {
        didSet {
            if UIScreen.main.bounds.maxY == 736 {
                constant = 5¨5_insh
            }
        }
    }
}

Don't forgot to inherit your class constraint from ConstraintLayout I will add the objective-c version soon

remy
  • 1,511
  • 10
  • 15
HamzaGhazouani
  • 6,464
  • 6
  • 33
  • 40
  • This is something new to me. Can you point out to more info about extending NSLayoutConstraint and how to use them with interface builder? – Evgeni Petrov Nov 16 '16 at 11:41
  • 1
    Could you please check this answer, if it's not clear for you I can upload a sample project with demo :) http://stackoverflow.com/questions/37411320/change-the-value-of-constraint-for-only-iphone-4-in-ib/37411321#37411321 – HamzaGhazouani Nov 16 '16 at 11:45
  • I understand! You subclass it and change the constraint class in IB. That was my missing thing! – Evgeni Petrov Nov 16 '16 at 12:03
  • Thanks @remy to update the code to swift 3. For swift 2 you can use the code in the screenshot :) – HamzaGhazouani Dec 27 '16 at 11:37
  • Thanks @HamzaGhazouani, This solved my problem i am struggling for 4 hr to find a way to do this without lots of code. – Surjeet Singh Sep 22 '17 at 11:57
  • @HamzaGhazouani - Could you please add objective-c version of the above code. Thanks in advance – user2552751 Feb 20 '18 at 11:44
1

The basic tool in Auto Layout to manage UI objects' position is the Constraints. A constraint describes a geometric relationship between two views. For example, you might have a constraint that says: “The right edge of progress bar is connected to the left edge of a lable 40 points of empty space between them.”

This means using AutoLayout you can't do conditional position setting based on UIDevice's mode, rather you can create a view layout which modifies itself if eg. the app runs on 3.5' full screen (IPhone4) or 4' full screen (IPhone5) based on the constraints.

So options for your problem using Constraints:

1) find a view on your layout which can be used to create a constraint to position the progressbar relatively. (select the view and the progressbar using CMD button, then use Editor/Pin/Vertical Spacing menu item to create a vertical constraint between the 2 objects)

2) create an absolute constraint to stick the progressbar's position to screen edge (keeping space) or centrally

I found helpful this tutorial about AutoLayout which might be beneficial for you also: http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

Pls note: autolayout only works from IOS 6.

nzs
  • 3,252
  • 17
  • 22
  • If you allow coding and not just using Interface Builder (as you said) you can consider using the Constraints as @Rob mentioned and of course simply adjust the progressbar's frame in viewDidLoad based on [[UIScreen mainScreen ] bounds ].size.height parameter (480->IPhone4 or below, 568->IPhone5) – nzs Apr 01 '13 at 22:29
  • I do allow coding, what I meant was that until that time I'd only used IB to set the constraints, I didn't know the updateViewConstraints method. Thanks, anyway. – Daniel Apr 02 '13 at 08:32
1

The new way, Without writing a single line!

No need to write device based conditions like these :-

if device == iPhoneSE { 
   constant = 44 
} else if device == iPhone6 {
   constant = 52
}

I created a library Layout Helper so now you can update constraint for each device without writing a single line of code.

enter image description here

Step 1

Assign the NSLayoutHelper to your constraint

enter image description here

Step 2

Update the constraint for the device you want

enter image description here

Step 3

Run the app and see the MAGIC

enter image description here

Community
  • 1
  • 1
tryKuldeepTanwar
  • 3,490
  • 2
  • 19
  • 49
0

I generally always try to stay in Interface Builder for setting up constraints. Diving in code to have more control is usually useful if you have completely different layouts on iPhone 4 and 6 for example.

As mentioned before, you can't have conditionals in Interface Builder, that's when linking a constraint to your view controller really comes handy.

Here's a short explanation on 3 approaches to solve Auto Layout issues for different screen sizes: http://candycode.io/how-to-set-up-different-auto-layout-constraints-for-different-screen-sizes/

Jure
  • 3,003
  • 3
  • 25
  • 28