简体   繁体   中英

How to set constraints for iPhone 5s or iPhone SE only using storyboard in autolayout?

I am trying to set the constraints using AutoLayout for a particular iPhone SE or 5s using storyboard.

Can you please suggest some screenshots using storyboard to handle the constraints for different IPhones only?

The distinction inside Storyboard between iPhoneSE and iPhone6/7 is something I am waiting for since a long time. But unfortunately, I had to realise that they have the same size-class and that therefore there is (to my knowledge) no possibility to set-up constraint-differences for the two inside Storyboards. (if I am wrong - please let me know !!).

However, you can do it in code.

You can use AnchorPoints or LayoutAnchors to set your constraints inside Code. But usually, the following does it for most of my cases :

I use a Switch-case around my UIDevice-ModelNames and set the Layout-Constraints for the iPhoneSE differently to the iPhone6/7 (or whatever Device I want to distinguish).

This being said, it is probably usually a good idea to create your Views (and its constraints with it) in Code entirely and without Storyboards. But I figured, for simple projects, it is still sometimes useful to quickly come up with a Storybard-Layout and also its Constraint-settings. Then I do the following to distinguish Devices :

在此处输入图片说明

// create the constraint-outlet by CTRL-drag
// one of your defined Constraint-lines from
// Storyboard directly to your Code

@IBOutlet weak var bannerWidthConstraint: NSLayoutConstraint!

// then for example inside viewDidLoad, set the outlet's constant to the value needed...
// Distinguish manually between UIDevices...
override func viewDidLoad() {    

    switch UIDevice.current.modelName {
    case Devices.IPhone5, Devices.IPhone5S, Devices.IPhone5C: 
         //, Devices.Simulator:
         self.bannerWidthConstraint.constant = 73
    case Devices.IPhone6, Devices.IPhone6S, Devices.IPhone7, Devices.IPhone8:
        //, Devices.Simulator:
        self.bannerWidthConstraint.constant = 96
    case Devices.IPhone6Plus, Devices.IPhone6SPlus, Devices.IPhone7Plus, Devices.IPhone8Plus:
        //, Devices.Simulator:
        self.bannerWidthConstraint.constant = 110
    case Devices.IPhoneX:
        //, Devices.Simulator:
        self.bannerWidthConstraint.constant = 96
    default:
        self.bannerWidthConstraint.constant = 73
    }
}

Remark: Please pay attention if you use the Simulator ! The Simulator has its own UIDevice-modelName and therefore you need to uncomment the Devices.Simulator comment in the Device-Size you are running you Simulator with (ie according to the Target your Simulator runs with!). --> Notize that each switch-case can be the Simulator-Device !!

And don't forget to define your Devices somewhere in your Code-Base: (--> of course, you need to update these when new Apple-Devices come out...)

public enum Devices: String {
    case IPodTouch5
    case IPodTouch6
    case IPhone4
    case IPhone4S
    case IPhone5
    case IPhone5C
    case IPhone5S
    case IPhone6
    case IPhone6Plus
    case IPhone6S
    case IPhone6SPlus
    case IPhone7
    case IPhone7Plus
    case IPhoneSE
    case IPhone8
    case IPhone8Plus
    case IPhoneX
    case IPad2
    case IPad3
    case IPad4
    case IPad5
    case IPadAir
    case IPadAir2
    case IPadMini
    case IPadMini2
    case IPadMini3
    case IPadMini4
    case IPadPro_9_7
    case IPadPro_12_9
    case IPadPro_12_9_2ndGen
    case IPadPro_10_5
    case AppleTV_5_3
    case AppleTV_6_2
    case HomePod
    case Simulator
    case Other
}

And...

public extension UIDevice {

    public var modelName: Devices {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8 , value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        switch identifier {
        case "iPod5,1":                                 return Devices.IPodTouch5
        case "iPod7,1":                                 return Devices.IPodTouch6
        case "iPhone3,1", "iPhone3,2", "iPhone3,3":     return Devices.IPhone4
        case "iPhone4,1":                               return Devices.IPhone4S
        case "iPhone5,1", "iPhone5,2":                  return Devices.IPhone5
        case "iPhone5,3", "iPhone5,4":                  return Devices.IPhone5C
        case "iPhone6,1", "iPhone6,2":                  return Devices.IPhone5S
        case "iPhone7,2":                               return Devices.IPhone6
        case "iPhone7,1":                               return Devices.IPhone6Plus
        case "iPhone8,1":                               return Devices.IPhone6S
        case "iPhone8,2":                               return Devices.IPhone6SPlus
        case "iPhone9,1", "iPhone9,3":                  return Devices.IPhone7
        case "iPhone9,2", "iPhone9,4":                  return Devices.IPhone7Plus
        case "iPhone8,4":                               return Devices.IPhoneSE
        case "iPhone10,1", "iPhone10,4":                return Devices.IPhone8
        case "iPhone10,2", "iPhone10,5":                return Devices.IPhone8Plus
        case "iPhone10,3", "iPhone10,6":                return Devices.IPhoneX
        case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return Devices.IPad2
        case "iPad3,1", "iPad3,2", "iPad3,3":           return Devices.IPad3
        case "iPad3,4", "iPad3,5", "iPad3,6":           return Devices.IPad4
        case "iPad4,1", "iPad4,2", "iPad4,3":           return Devices.IPadAir
        case "iPad5,3", "iPad5,4":                      return Devices.IPadAir2
        case "iPad6,11", "iPad6,12":                    return Devices.IPad5
        case "iPad2,5", "iPad2,6", "iPad2,7":           return Devices.IPadMini
        case "iPad4,4", "iPad4,5", "iPad4,6":           return Devices.IPadMini2
        case "iPad4,7", "iPad4,8", "iPad4,9":           return Devices.IPadMini3
        case "iPad5,1", "iPad5,2":                      return Devices.IPadMini4
        case "iPad6,3", "iPad6,4":                      return Devices.IPadPro_9_7
        case "iPad6,7", "iPad6,8":                      return Devices.IPadPro_12_9
        case "iPad7,1", "iPad7,2":                      return Devices.IPadPro_12_9_2ndGen
        case "iPad7,3", "iPad7,4":                      return Devices.IPadPro_10_5
        case "AppleTV5,3":                              return Devices.AppleTV_5_3
        case "AppleTV6,2":                              return Devices.AppleTV_6_2
        case "AudioAccessory1,1":                       return Devices.HomePod
        case "i386", "x86_64":                          return Devices.Simulator
        default:                                        return Devices.Other
        }
    }
}

iPhone SE and iPhone 6/7 have the same size class. So, all the constraints you created for SE will be applied for 6 too. But you can manipulate them from code. Check UIScreen.main.bounds and update your constraints in code if necessary.

You can set constraints with defrance Device using variants. but have used Xcode 8.0 here is one new option Vary for Traits.

For example, you need a button having different widths in iPhone and iPad, then it can be easily done and viewed at the same time rather than the earlier Size classes wherein for checking each layout , we had to open the preview and select devices.

I have added a button with fixed width 135.

在此处输入图片说明

If we select an iPad screen now, it shows like在此处输入图片说明

Now if we want to change the size for iPad, then click on the button in the bottom-right corner "Vary for Traits". Now you are good to go with selecting landscape or portrait orientations as per need. Also select height & width tickboxes.

在此处输入图片说明

I am now changing the width constant to 500.

在此处输入图片说明

Then as a confirmation, we need to click on "Done varying" button. After which the screen looks like

在此处输入图片说明

Now when you go back to any of the iPhone devices, the width constraint will be the same as earlier set in iPhone device.

在此处输入图片说明

That was all about "Vary Traits". I do accept that on working with "Traits" while changing between different iPhone/iPad + Orientaion combinations there are bugs that some constraints go missing.

So just to be on safe side, I request to keep in mind the Size class values for various screen layouts as in

在此处输入图片说明

Let me know you have any query.

This is not great, but at least is little easier than doing everything in code.

So, eg if you want different constraints for LoginViewController, you can create two xibs: LoginViewControllerSE.xib (for SE) and LoginViewController.xib (for other phones) and then create initializer:

init() {
    if UIDevice.current.modelName == Devices.IPhoneSE {
        super.init(nibName: "LoginViewControllerSE", bundle: nil)
    } else {
        super.init(nibName: nil, bundle: nil)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM