自动布局 vs 框架尺寸

10

所以,我有点尴尬地问这个问题,因为它似乎是如此基础,但自从开始iOS开发(大约一年的自学/网络教学)以来,当不使用storyboards时,我严重依赖frame大小,并很少使用自动布局。在Objective C中,我发现自己需要更经常地使用自动布局,但是用Swift,我可以动画化一个框架的x和y起源、它的中心等等…我从来没有遇到过一个情况,在那里我不能仅仅通过框架大小和像素位置来实现我想要的,并且我已经完成了一些相当复杂的视图工作。我的问题是,使用自动布局而不是框架大小和像素位置的好处是什么?我不想因为无知和习惯而错过一些伟大的性能优势。非常感谢!


如果可以在没有自动布局的情况下实现预期的UI,则应该选择基于框架的布局。自动布局依赖于计算约束以生成框架。约束越多,计算量就越大。 - BangOperator
@BangOperator 是完全正确的。这不是一个“这个还是那个”的问题,你必须意识到什么时候需要自动布局,以及什么时候可以轻松地不使用它。自动布局很快就会变得昂贵。它是一个强大的工具,但如果使用不当会引起问题。 - Allison
这个问题的答案可以在这里找到。作为一个新手iOS开发者,我个人认为它比本页上的答案更好地回答了这个问题。 - Ben Butterworth
@BenButterworth 您的链接指向了这个问题本身。您可能想要其他链接。 - HangarRash
4个回答

19

tl;dr 学会如何使用自动布局,这对于实际应用程序是一个巨大的时间节省器!

长篇回答:

最终,您是否要使用Apple提供的Auto Layout或Size Classes等功能取决于您。这些的主要好处并不真正体现在最终产品中UI渲染方面的性能。而是你需要投入的时间来考虑所有边缘情况,如果你计划开发一个可以在不同屏幕大小和方向上工作的应用程序。

假设你想做所有需要支持iPhone 4 / 4s屏幕大小,iPhone 5 / 5s屏幕大小,iPhone 6 / 6s(Plus)屏幕大小和iPad屏幕大小以及所有上述屏幕大小的纵向和横向模式的工作( 这里有一个很好的概述):没有问题,就这样做。您当然需要非常仔细地测试事物,并且始终保持此列表最新-在每个应用程序中,您都使用自己的解决方案。如果适合您,请这样做。

但是,大多数人想要把他们的想法传达出去,而不必过多地考虑不同的屏幕大小等问题。您当然可以从一个应用程序中提取自己的逻辑,以在所有应用程序中使用它,这正是Auto Layout和Screen Sizes所关注的内容。简单地说,Apple已经为您做好了在不同屏幕上进行框架设置的工作。 您只需要使用他们的新词汇(约束)使其工作即可。

换句话说:它是对直接处理屏幕渲染逻辑的抽象层。如果您不喜欢它,请放手。但是,如果您计划开发一些严肃的应用程序,这些应用程序应该在不同的iPhone / iPad代数上工作,并且还计划维护这些应用程序,则请学习如何使用Auto Layout和Size Classes。这将节省您和所有未来维护者相当多的开发时间。

一个很好的起点是文档。或者像这个教程一样,在raywenderlich.com上学习。
苹果在上面提到的文档中谈到了这个难点:
在许多方面,以编程方式定义视图的框架提供了最大的灵活性和功能。当发生变化时,可以实现任何想要的更改。然而,因为您也必须自己管理所有更改,所以布局简单的用户界面需要设计、调试和维护相当多的工作。创建一个真正适应性强的用户界面会将难度提高一个数量级。
顺便说一下:
使用自动布局或框架在编程语言方面没有任何区别:Swift 和 Objective-C都可以完美地支持两种方式。看来你只是还没有找到如何在 Obj-C 中更改框架。 ;)
还有一件事:
您也不需要使用Storyboards来使用Auto Layout。您可以从代码中使用Auto Layout。在此处查看文档。甚至有许多框架试图使这更加简单(来自苹果的原始API在许多方面都不太好看),我可以推荐SnapKit

我主要是想知道 UI 渲染是否有任何差异,可能我没有表达清楚。这个问题涉及到性能优势。你已经为我澄清了这一点,非常感谢!然而,如果我没记错的话,这两种语言在处理框架方面确实有所不同。我还没有找到一种在 Objective-C 中独立设置框架 x 或 y 原点的方法,而不必显式地重新创建整个框架。Swift 的行为不同,或者至少更加明显。此外,我经常以编程方式编写约束条件。我只是更经常使用另一种替代方法。 - Matt Clevenger
我很有可能会把自动布局作为我的常规使用方法,因为绝大多数开发人员都拥护它,而且我从来没有遇到过任何麻烦。虽然我一直都不介意框架大小。再次感谢您的见解! - Matt Clevenger
1
不用谢。很高兴我能帮到你。而且,在Objective-C中,你只能分配整个CGRect对象(整个框架),这是一种方法,直到Swift通过实现CGRect作为Swift Struct结构引入了更好的方法。然而,Swift Structs与Objective-C不兼容,所以它们仍然以旧方式集成(C structs,我认为),这就是为什么在Obj-C中更改单个值仍然比在Swift中更麻烦的原因。 - Jeehut
您可以构建一个没有自动布局的UI,以适应任何设备大小。如果您使用超级视图的宽度通过编程方式设置视图的框架,则无需额外工作即可在iPhone 7或4上获得良好的UI效果。当视图在应用程序运行时发生更改(例如更改设备方向或电话呼入并且状态栏的高度加倍)时,自动布局会被使用。事实是,苹果的文档,特别是在编程工作方面,非常简洁,因此要使自动布局正好按照您想要的方式工作需要大量的试错和互联网搜索。 - lurning too koad
我认为这个人说得很对。性能的好处可能不在于渲染,而是在于生产力、维护、未来的保障等方面。此外,在iOS 12中,自动布局变得更加出色和高效。 - Lucas Chwe

3
依赖框架大小等于计算大小。使用百分比或比例时,可能适用于各种手机型号,但在某些分辨率上仍可能看起来有些奇怪。此时,您需要添加另一个条件语句,因为例如在iPhone 4s上,您将希望有稍微不同的布局。您的代码越来越复杂,可能会导致任何更改都存在风险。这是可行的,但为什么要重新发明轮子呢?
像基本约束这样的工具有时会替换掉对于布局而言真正庞大的逻辑块。压缩第二个标签时,将逻辑转换为少量的if语句。考虑一下10个标签。随着大小类别、启用/禁用约束、压缩和拥抱等功能的增加,自动布局已经成为我无法替代的选择,我建议您了解一下它,因为大多数公司都在使用它,即使不是在storyboards中,也是在xibs或代码中使用自动布局。

0

自动布局被开发出来是为了让程序员能够在iOS上编写适用于任意尺寸屏幕和视图的程序。之前,在前四代iPhone上,iOS开发人员只能针对一个屏幕大小进行设计,但随着最近的历史表明,苹果愿意制造不同形状和大小的硬件。自动布局提供了一种方便的方式来创建适应不同屏幕和视图尺寸的用户界面。可以开发没有自动布局的UI来充分利用不同的视图尺寸吗?可以。但要创建具有多个UI元素的真正可调整大小的视图,通常程序员必须将一个元素的大小设置相对于其他已经被调整大小和定位的UI元素。例如:

NSString *nameString = [NSString stringWithFormat:@"%@", self.name];
        CGSize nameSize = [nameString sizeWithAttributes:attribs];

        [nameString drawAtPoint:CGPointMake(self.bounds.size.width*0.5-nameSize.width*0.5, IMAGE_INSET+4*CONTENT_BUFFER(self.bounds.size.height)+facePicHeight) withAttributes:attribs];

        questionFont = [UIFont systemFontOfSize:self.bounds.size.height*0.025];
        attribs = @{NSFontAttributeName: questionFont, NSParagraphStyleAttributeName:paragraphStyle};

        NSString *maleString = [NSString stringWithFormat:@"%@", self.male];
        CGSize maleSize = [maleString sizeWithAttributes:attribs];
        [maleString drawAtPoint:CGPointMake(self.bounds.size.width*0.5-maleSize.width*0.5,
                                            IMAGE_INSET+5*CONTENT_BUFFER(self.bounds.size.height)+facePicHeight+nameSize.height) withAttributes:attribs];

        NSString *femaleString = [NSString stringWithFormat:@"%@", self.female];
        CGSize femaleSize = [femaleString sizeWithAttributes:attribs];
        [femaleString drawAtPoint:CGPointMake(self.bounds.size.width*0.5-femaleSize.width*0.5,
                                              IMAGE_INSET+6*CONTENT_BUFFER(self.bounds.size.height)+facePicHeight+nameSize.height+maleSize.height) withAttributes:attribs];

        NSString *babyString = [NSString stringWithFormat:@"%@", self.baby];
        CGSize babySize = [babyString sizeWithAttributes:attribs];
        [babyString drawInRect:CGRectMake(IMAGE_INSET+CONTENT_BUFFER(self.bounds.size.height), IMAGE_INSET+7*CONTENT_BUFFER(self.bounds.size.height)+facePicHeight+nameSize.height+maleSize.height+femaleSize.height, self.bounds.size.width-2.0*(IMAGE_INSET+CONTENT_BUFFER(self.bounds.size.height)), babySize.height) withAttributes:attribs];

整个过程可能会变得有些笨重。显然,有些视图比其他视图更简单,但如果您有一个复杂的视图,想要支持多任务处理、本地化和其他会影响用户界面布局的功能,那么使用自动布局通常会更容易。

0

iOS基于框架和自动布局

基于框架 - 通过(x,y,宽度,高度)进行定位。在多屏幕情况下需要进行大量计算和变量处理。

let customView = CustomView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
customView.translatesAutoresizingMaskIntoConstraints = true

自动调整掩码是基于父视图的视图调整大小的行为。增加了一些动态性。

view.autoresizingMask = [.flexibleRightMargin]

自动布局 - 使用约束来设置视图之间的关系。视图的框架根据约束动态计算。这增加了理论上对性能的影响,但另一方面更加友好。

let customView = CustomView()
customView.translatesAutoresizingMaskIntoConstraints = false
customView.widthAnchor.constraint(equalToConstant: 50).isActive = true
...

自动布局引擎

measurement(subView->superView) -> layout(superView->subView)


使用view.translatesAutoresizingMaskIntoConstraints = false来使用AutoLayout。在InterfaceBuilder中,默认情况下为false,在以编程方式创建视图时为true。如果您在代码中创建视图,则必须手动将其设置为false
view.translatesAutoresizingMaskIntoConstraints = false // false for autolayout

view.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 16).isActive = true

在编程中,可以使用AutoLayout和UITableView.automaticDimension来设置func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat,这样就不用考虑视图的高度。

当视图已经添加到打印视图中时,也可以设置约束。

parentView.addSubview(view)
view.topAnchor.constraint(equalTo: self.topAnchor, constant: 16).isActive = true

或者你得到

Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接