Лучшие практики для программного использования автоматического размещения - PullRequest
0 голосов
/ 09 апреля 2020

Я использую auto layout для всего своего приложения программно, но я действительно изо всех сил стараюсь, чтобы мое приложение выглядело хорошо на всех устройствах (особенно борюсь с iPhone SE). Вот пример моего StartViewController (SE, 8 и 11 Pro Max):

Как вы можете видеть, вид выглядит довольно хорошо на iPhone 8 и 11 Pro Макс. Однако на iPhone SE это довольно плохо. Я не совсем понимаю, почему, потому что было бы достаточно места для размещения всех видов, как в iPhone 8 ?? По некоторым причинам я думаю, что buttons и labels больше (возможно, это просто иллюзия).

Мой вопрос: как я могу решить эту проблему? Каковы лучшие практики? Сокращение fontSize? Делать buttons меньше? Каков наилучший способ получить динамический макет c, который работает для каждого iPhone? Видимо я использую Auto-Layout не лучшим образом ...

Вот как я ограничиваю views из картинки:

//MARK: setupViews
func setUpViews(){

    view.addSubview(backgroundImage)
    view.addSubview(willkommenLabel)
    view.addSubview(textLabel)
    view.addSubview(emailButton)
    emailButton.addSubview(emailImage)
    view.addSubview(oderLabel)
    view.addSubview(lineLeft)
    view.addSubview(lineRight)
    view.addSubview(facebookButton)
    facebookButton.addSubview(facebookLogo)
    view.addSubview(googleButton)
    googleButton.addSubview(googleLogo)
    view.addSubview(appleButton)
    appleButton.addSubview(appleLogo)
    view.addSubview(documentsLabel)

    backgroundImage.topAnchor.constraint(equalTo: view.topAnchor, constant: -20).isActive = true
    backgroundImage.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 20).isActive = true
    backgroundImage.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -20).isActive = true
    backgroundImage.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 20).isActive = true

    willkommenLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 80).isActive = true
    willkommenLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    willkommenLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true


    textLabel.topAnchor.constraint(equalTo: willkommenLabel.bottomAnchor, constant: 30).isActive = true
    textLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    textLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true

    emailButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    emailButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
    emailButton.topAnchor.constraint(equalTo: textLabel.topAnchor, constant: 100).isActive = true
    emailButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    emailImage.centerYAnchor.constraint(equalTo: emailButton.centerYAnchor).isActive = true
    emailImage.leadingAnchor.constraint(equalTo: emailButton.leadingAnchor, constant: 10).isActive = true
    emailImage.heightAnchor.constraint(equalToConstant: 25).isActive = true
    emailImage.widthAnchor.constraint(equalToConstant: 25).isActive = true

    oderLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    oderLabel.bottomAnchor.constraint(equalTo: emailButton.bottomAnchor, constant: 40).isActive = true
    oderLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true

    lineLeft.centerYAnchor.constraint(equalTo: oderLabel.centerYAnchor).isActive = true
    lineLeft.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    lineLeft.trailingAnchor.constraint(equalTo: oderLabel.leadingAnchor).isActive = true

    lineRight.centerYAnchor.constraint(equalTo: oderLabel.centerYAnchor).isActive = true
    lineRight.leadingAnchor.constraint(equalTo: oderLabel.trailingAnchor).isActive = true
    lineRight.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true

    facebookButton.leadingAnchor.constraint(equalTo: emailButton.leadingAnchor).isActive = true
    facebookButton.trailingAnchor.constraint(equalTo: emailButton.trailingAnchor).isActive = true
    facebookButton.bottomAnchor.constraint(equalTo: oderLabel.bottomAnchor, constant: 55 + 10).isActive = true
    facebookButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    facebookLogo.centerYAnchor.constraint(equalTo: facebookButton.centerYAnchor).isActive = true
    facebookLogo.leadingAnchor.constraint(equalTo: facebookButton.leadingAnchor, constant: 10).isActive = true
    facebookLogo.heightAnchor.constraint(equalToConstant: 25).isActive = true
    facebookLogo.widthAnchor.constraint(equalToConstant: 25).isActive = true

    googleButton.leadingAnchor.constraint(equalTo: emailButton.leadingAnchor).isActive = true
    googleButton.trailingAnchor.constraint(equalTo: emailButton.trailingAnchor).isActive = true
    googleButton.bottomAnchor.constraint(equalTo: facebookButton.bottomAnchor, constant: 55 + 10).isActive = true
    googleButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    googleLogo.centerYAnchor.constraint(equalTo: googleButton.centerYAnchor).isActive = true
    googleLogo.leadingAnchor.constraint(equalTo: googleButton.leadingAnchor, constant: 10).isActive = true
    googleLogo.heightAnchor.constraint(equalToConstant: 25).isActive = true
    googleLogo.widthAnchor.constraint(equalToConstant: 25).isActive = true

    appleButton.leadingAnchor.constraint(equalTo: emailButton.leadingAnchor).isActive = true
    appleButton.trailingAnchor.constraint(equalTo: emailButton.trailingAnchor).isActive = true
    appleButton.bottomAnchor.constraint(equalTo: googleButton.bottomAnchor, constant: 55 + 10).isActive = true
    appleButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    appleLogo.centerYAnchor.constraint(equalTo: appleButton.centerYAnchor).isActive = true
    appleLogo.leadingAnchor.constraint(equalTo: appleButton.leadingAnchor, constant: 10).isActive = true
    appleLogo.heightAnchor.constraint(equalToConstant: 25).isActive = true
    appleLogo.widthAnchor.constraint(equalToConstant: 25).isActive = true

    documentsLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
    documentsLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
    documentsLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -5).isActive = true

}

Ответы [ 3 ]

1 голос
/ 12 апреля 2020

Попробуйте.

Используется несколько процентов высоты (в зависимости от вашего исходного макета на экране iPhone 8).

Я не изменил ни один из ваших существующих код. Просто добавьте следующее func и измените свой вызов с:

setupViews()

на

setupViewsDon()

Должно быть ясно из комментариев, где вы можете внести какие-либо корректировки ... но надеюсь, это приблизит вас к вашей цели - и, возможно, вы найдете несколько советов для будущего использования:

func setupViewsDon(){

    // setting these properties here, so I don't have to change your original initialization
    willkommenLabel.numberOfLines = 1
    willkommenLabel.adjustsFontSizeToFitWidth = true
    willkommenLabel.minimumScaleFactor = 0.5

    textLabel.numberOfLines = 2
    textLabel.adjustsFontSizeToFitWidth = true
    textLabel.minimumScaleFactor = 0.5

    // prevent willkommenLabel from being compressed or streched
    willkommenLabel.setContentHuggingPriority(.required, for: .vertical)
    willkommenLabel.setContentCompressionResistancePriority(.required, for: .vertical)

    // prevent oderLabel from being compressed or streched
    oderLabel.setContentHuggingPriority(.required, for: .vertical)
    oderLabel.setContentCompressionResistancePriority(.required, for: .vertical)

    // prevent documentsLabel from being compressed or streched
    documentsLabel.setContentHuggingPriority(.required, for: .vertical)
    documentsLabel.setContentCompressionResistancePriority(.required, for: .vertical)

    view.addSubview(backgroundImage)
    view.addSubview(willkommenLabel)
    view.addSubview(textLabel)
    view.addSubview(emailButton)
    emailButton.addSubview(emailImage)
    view.addSubview(oderLabel)
    view.addSubview(lineLeft)
    view.addSubview(lineRight)
    view.addSubview(facebookButton)
    facebookButton.addSubview(facebookLogo)
    view.addSubview(googleButton)
    googleButton.addSubview(googleLogo)
    view.addSubview(appleButton)
    appleButton.addSubview(appleLogo)
    view.addSubview(documentsLabel)

    backgroundImage.topAnchor.constraint(equalTo: view.topAnchor, constant: -20).isActive = true
    backgroundImage.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 20).isActive = true
    backgroundImage.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -20).isActive = true
    backgroundImage.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 20).isActive = true

    // add a layout guide for percentage top spacing
    let topSpaceGuide = UILayoutGuide()
    view.addLayoutGuide(topSpaceGuide)

    // based on iPhone 8 ... 80-pts from top
    // will be shorter on smaller devices, taller on larger devices
    topSpaceGuide.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    topSpaceGuide.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 80.0 / 667.0).isActive = true

    willkommenLabel.topAnchor.constraint(equalTo: topSpaceGuide.bottomAnchor).isActive = true
    willkommenLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    willkommenLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true

    // textLabel top constrained to willkommenLabel bottom
    textLabel.topAnchor.constraint(equalTo: willkommenLabel.bottomAnchor, constant: 0).isActive = true
    textLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    textLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true

    // textLabel height = a percentage of view height using 100-pts based on an iPhone 8
    //  priority = .defaultHigh so it can be compressed if needed (on smaller devices)
    let c = textLabel.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 100.0 / 667.0)
    c.priority = .defaultHigh
    c.isActive = true

    // set email button height
    emailButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

    // set other button heights equal to emailButton
    facebookButton.heightAnchor.constraint(equalTo: emailButton.heightAnchor).isActive = true
    googleButton.heightAnchor.constraint(equalTo: emailButton.heightAnchor).isActive = true
    appleButton.heightAnchor.constraint(equalTo: emailButton.heightAnchor).isActive = true

    // add the logo images to the buttons, and make their heights relative to button heights
    //      in case you want to change the button heights

    for (btn, img) in [(emailButton, emailImage), (facebookButton, facebookLogo), (googleButton, googleLogo), (appleButton, appleLogo)] {
        btn.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
        btn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
        btn.addSubview(img)
        img.centerYAnchor.constraint(equalTo: btn.centerYAnchor).isActive = true
        img.leadingAnchor.constraint(equalTo: btn.leadingAnchor, constant: 10).isActive = true
        img.heightAnchor.constraint(equalTo: btn.heightAnchor, multiplier: 0.5).isActive = true
        img.widthAnchor.constraint(equalTo: img.heightAnchor).isActive = true
    }

    emailButton.topAnchor.constraint(equalTo: textLabel.bottomAnchor, constant: 20).isActive = true
    oderLabel.topAnchor.constraint(equalTo: emailButton.bottomAnchor, constant: 15).isActive = true
    facebookButton.topAnchor.constraint(equalTo: oderLabel.bottomAnchor, constant: 15).isActive = true
    googleButton.topAnchor.constraint(equalTo: facebookButton.bottomAnchor, constant: 10).isActive = true
    appleButton.topAnchor.constraint(equalTo: googleButton.bottomAnchor, constant: 10).isActive = true

    // make sure appleButton stays above documentsLabel
    appleButton.bottomAnchor.constraint(lessThanOrEqualTo: documentsLabel.topAnchor, constant: -20.0).isActive = true

    // horizontal arrangement of oderLabel and left/right lines
    oderLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    oderLabel.widthAnchor.constraint(equalToConstant: 60).isActive = true

    lineLeft.centerYAnchor.constraint(equalTo: oderLabel.centerYAnchor).isActive = true
    lineLeft.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    lineLeft.trailingAnchor.constraint(equalTo: oderLabel.leadingAnchor).isActive = true

    lineRight.centerYAnchor.constraint(equalTo: oderLabel.centerYAnchor).isActive = true
    lineRight.leadingAnchor.constraint(equalTo: oderLabel.trailingAnchor).isActive = true
    lineRight.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true

    // documentsLabel stay at bottom
    documentsLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
    documentsLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
    documentsLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -5).isActive = true

}
0 голосов
/ 12 апреля 2020

Если вы хотите, чтобы ваш дизайн работал идеально на всех устройствах, вам следует избегать установки постоянных значений настолько, насколько это возможно, если это не необходимо, здесь вы устанавливаете фиксированные значения высоты и отступов, пытаясь установить их в зависимости от размера экрана, например, здесь вы можете установить все кнопки в виде и установить его высоту равной половине экрана:

  Let height = view.frame.size.height / 2
  buttonView.heightAnchor.constrains(equalTo: height).isActive = true

А также вставить кнопки внутри стека. Представление покрывает представление кнопок и установить его одинаковое заполнение для кнопок. , Таким образом, все кнопки должны быть одинаково и не жестко запрограммированы, а также динамически c вид кнопок, относящихся к размеру экрана, на каком устройстве запущено приложение

0 голосов
/ 09 апреля 2020

На самом деле это зависит от того, как вы хотите, чтобы макет выглядел на каждом устройстве, поэтому, если вы хотите установить фиксированную высоту для всех элементов, вам следует обернуть все элементы внутри прокрутки, которая будет прокручиваться для небольших устройств и действовать, если она не существует на больших устройствах. или, если вам нужно, чтобы элементы помещались на экране во всех устройствах, вы должны установить ограничения по высоте, пропорциональные высоте экрана

...