Pull to refresh

Мои 3 способа для выравнивания UI на разных девайсах в Swift

Reading time3 min
Views2.1K

Итак, первый классический - обычный NSLayoutConstraint. Удобный, нативный и нисколько не обременяющий в написании. Но что если ваше приложение должно работать на iPhone SE 1 поколения? Тогда с вероятностью в 100% где-то вёрстка поедет. Для этого случая вы можете использовать UIDevice.current.

Второй помощник - UIDevice.current. Эта переменная, которую вы можете сами прописать в extension UIDevice. Она позволяет вам высчитывать размеры текущего устройства и исходя из этого создавать другие переменные и делегировать устройства по группам: таким, как isSmallScreen/isXScreenDevice . Но даже этого не всегда бывает достаточно, и приходится отказываться от разного рода дизайнерских решений.

extension UIDevice {
    var iPhone: Bool {
        return UIDevice().userInterfaceIdiom == .phone
    }

    enum ScreenType: String {
        case iPhone8
        case iPhone8Plus
        case iPhoneX
        case iPhoneXSMax
        case iPhone11
        case iPhone11Pro
        case iPhoneSE
        case iPhone12
        case iPhone12Pro
        case iPhone12Mini
        case Unknown
    }

    var current: ScreenType {
        guard iPhone else { return .Unknown}
        
        switch UIScreen.main.nativeBounds.height {
        case 1136:
            return .iPhoneSE
        case 1334:
            return .iPhone8
        case 2208:
            return .iPhone8Plus
        case 2436:
            return .iPhoneX
        case 2521:
            return .iPhone12
        case 2532:
            return .iPhone11Pro
        case 2688:
            return .iPhoneXSMax
        case 2778:
            return .iPhone12Pro
        case 1792:
            return .iPhone11
        default:
            return .Unknown
        }
    }
}

И третий, о котором я узнал лишь на первой работе и больше нигде его не применял. Для этого мы создаём константы screenHeight и screenWidth, которые равны UIScreen.main.bounds.height/width . При использовании в NSLayoutConstraint придерживаемся такой формулировки:

// Для вертикальных констрейнтов (например topAnchor, bottomAnchor)
20/812*screenHeight
// Для горизонтальных констрейнтов (например leadingAnchor, trailingAnchor)
20/375*screenWidth

Этот вариант практически идеально позволяет распределить UI-объекты на разных устройствах, и элементы вашего приложения будут выглядеть всегда одинаково и на iPhone 14 Pro Max, и на iPhone SE.

При первом взгляде это самый подходящий вариант. Однако чем чаще его используешь, тем больше приходит понимание, что это не панацея, а скорее не нужный, объёмный "костыль", который заполоняет весь код магическими числами и непременно вызовет негодование у вашего тимлида. Поэтому я бы рекомендовал его использовать только в редких случаях.

NSLayoutConstraint.activate([
            secondTitleLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -156/812*screenHeight),
            secondTitleLabel.rightAnchor.constraint(equalTo: view.rightAnchor),
            secondTitleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            secondTitleLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
        ])
        
        NSLayoutConstraint.activate([
            mainTitleLabel.bottomAnchor.constraint(equalTo: secondTitleLabel.topAnchor, constant: -32/375*screenWidth),
            mainTitleLabel.rightAnchor.constraint(equalTo: view.rightAnchor),
            mainTitleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            mainTitleLabel.leftAnchor.constraint(equalTo: view.leftAnchor)
        ])

В заключение скажу, что спустя время я чаще прибегаю к обычной работе констрейнтов, и их всегда хватает с головой. Иногда в редких случаях я использую UIDevice.current. И практически никогда третий вариант.

Экспериментируйте! Если найдёте для себя полезным тот или иной вариант, попробуйте его в своём проекте. Если я упустил что-то, не стесняйтесь поделиться этим в комментариях.

Надеюсь, эта статья была для вас полезна.

Tags:
Hubs:
Total votes 5: ↑2 and ↓3-1
Comments26

Articles