Ios 以编程方式使用自动布局的最佳实践
我在整个应用程序中以编程方式使用Ios 以编程方式使用自动布局的最佳实践,ios,swift,autolayout,constraints,Ios,Swift,Autolayout,Constraints,我在整个应用程序中以编程方式使用自动布局,但我真的很难让我的应用程序在所有设备上看起来都很好(尤其是在iPhone SE上)。以下是我的StartViewController(SE,8&11 Pro Max)示例: 正如你所看到的,在iPhone8和11 Pro Max上的视图看起来相当不错,但在iPhoneSE上却相当糟糕。我不太明白为什么,因为会有足够的空间来布局所有视图,就像iPhone8一样??出于某种原因,我认为按钮和标签更大(可能只是一种错觉) 我的问题是如何解决这个问题?什么是最
自动布局
,但我真的很难让我的应用程序在所有设备上看起来都很好(尤其是在iPhone SE上)。以下是我的StartViewController
(SE,8&11 Pro Max)示例:
正如你所看到的,在iPhone8和11 Pro Max上的视图看起来相当不错,但在iPhoneSE上却相当糟糕。我不太明白为什么,因为会有足够的空间来布局所有视图,就像iPhone8一样??出于某种原因,我认为按钮
和标签
更大(可能只是一种错觉)
我的问题是如何解决这个问题?什么是最佳实践?收缩fontSize
?是否将按钮变小?获得适用于所有iPhone的动态布局的最佳方法是什么?显然,我使用的自动布局不是最好的方式
下面是我如何从图片中约束视图
:
//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
}
实际上,这取决于您如何在每个设备中查看布局,因此如果您希望所有元素的高度都固定,那么您应该将所有元素包装在滚动视图中,滚动视图将显示小型设备,如果大型设备中不存在,则采取行动,或者,如果您需要使所有设备中的元素都适合屏幕,那么您应该使高度约束与屏幕高度成比例,试试看
它使用了几个百分比的高度(基于iPhone8屏幕上的原始布局)
我没有更改你现有的任何代码。只需添加以下func
并将您的通话从:
setupViews()
到
从评论中可以清楚地看出,您可能需要在哪里进行任何调整。。。但希望这能让你接近你的目标——也许你会找到一些未来使用的技巧:
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
}
如果你想让你的设计在所有设备上都能完美运行,那么你必须尽可能避免设置常量值,除非有必要,在这里你要设置高度和填充物的固定数字,试图设置它们与屏幕大小相关,例如,您可以在此处设置视图中的所有按钮,并将其高度设置为屏幕的一半:
Let height = view.frame.size.height / 2
buttonView.heightAnchor.constrains(equalTo: height).isActive = true
并将按钮插入stackView中,以覆盖按钮视图,并将其设置为按钮填充相等。因此,您将拥有所有相同的按钮,而不是硬编码,以及与运行应用程序的任何设备的屏幕大小相关的按钮动态视图我在另一个视图控制器中使用的滚动视图
。但在我看来,对于第一个屏幕,ScrollView是非常不直观的。那么这里的UI规则是什么?只需将按钮和标签缩小??我怎样才能动态生成fontSize?这是一个设计问题,但对我来说,我更喜欢缩放它,而不是让它滚动,您可以使用scaleFont来适应label/button的属性。您可以创建一个vc函数扩展来检测当前设备,并返回创建所有元素时使用的字体大小。因为设计并不像人们想象的那么简单。这就是为什么优秀的设计师会得到很好的报酬。看起来你的“Willkomen…”标签上方的空间太大了;您可能希望在“Werde Mitglied…”标签上启用“自动收缩”;在较小的设备上,您可能希望按钮稍微短一点;对不起,我当时很忙,现在才知道答案。这太完美了!!非常好的工作,非常感谢。正是我想要的。如果我有任何不清楚的地方,我会检查代码并告诉您:)我创建了一个房间:
Let height = view.frame.size.height / 2
buttonView.heightAnchor.constrains(equalTo: height).isActive = true