【问题标题】:Best Practices for programmatically using autolayout以编程方式使用自动布局的最佳实践
【发布时间】:2020-07-22 02:27:39
【问题描述】:

我在整个应用程序中以编程方式使用auto layout,但我真的很难让我的应用程序在所有设备上看起来都很好(尤其是在 iPhone SE 上苦苦挣扎)。这是我的StartViewController(SE、8 和 11 Pro Max)的示例:

如您所见,iPhone 8 和 11 Pro Max 上的视图看起来相当不错。但是在 iPhone SE 上,它非常糟糕。我不太明白为什么,因为会有足够的空间来布局所有视图,就像在 iPhone 8 中一样?出于某种原因,我认为buttonslabels 更大(可能只是一种错觉)。

我的问题是如何解决这个问题?什么是最佳实践?缩小fontSize?使buttons 更小?获得适用于每部 iPhone 的动态布局的最佳方法是什么?显然我没有以最好的方式使用自动布局......

这是我如何约束图片中的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

}

【问题讨论】:

  • UI 设计并不像人们想象的那么简单。这就是为什么非常优秀的设计师得到报酬非常丰厚的钱。看起来您的“Willkommen...”标签上方的空间太大了;您可能希望在“Werde Mitglied...”标签上启用“自动收缩”;您可能希望在较小的设备上按钮更短一些;我们。

标签: ios swift autolayout constraints


【解决方案1】:

试试这个。

它使用几个百分比高度(基于您在 iPhone 8 屏幕上的原始布局)。

我没有更改您现有的任何代码。只需添加以下 func 并更改您的呼叫:

setupViews()

setupViewsDon()

应该从 cmets 中明确您可能想要进行任何调整的地方...但希望这会让您接近您的目标 - 也许您会找到一些提示以供将来使用:

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

}

【讨论】:

【解决方案2】:

实际上,这取决于您希望布局如何在每个设备中查看,因此如果您想要所有元素的固定高度,那么您应该将所有元素包装在一个滚动视图中,该滚动视图将为小型设备滚动,如果不存在于大型设备中则采取行动,或者如果您需要使元素适合所有设备的屏幕,那么您应该使高度限制与屏幕高度成比例

【讨论】:

  • 我在另一个ViewController 中使用ScrollView。但是对于第一个屏幕,我认为 ScrollView 非常不直观。那么这里的UI 规则 是什么?只是让按钮和标签更小??我怎样才能动态地制作 fontSize ?
  • 这是一个设计的东西,但对我来说我更喜欢缩放它而不是让它滚动,你可以使用 scaleFont 来适应标签/按钮的属性你可以创建一个检测到当前设备的 vc 函数扩展并返回创建所有元素时使用的字体大小
【解决方案3】:

如果您希望您的设计在所有设备上都能完美运行,那么您必须尽可能避免设置常量值,除非有必要,在这里您设置高度和填充固定数字,尝试将它们设置为与屏幕尺寸相关,例如,您可以在此处设置视图中的所有按钮并将其高度设置为屏幕的一半:

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

并且还将按钮插入到 stackView 中,覆盖按钮视图并将其设置为对按钮进行平均填充。因此,您将拥有所有按钮平等而不是硬编码,以及与运行应用程序的任何设备的 ro 屏幕大小相关的按钮动态视图

【讨论】:

    猜你喜欢
    • 2020-05-23
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多