【问题标题】:Can I use setFrame and autolayout on the same view?我可以在同一个视图上使用 setFrame 和 autolayout 吗?
【发布时间】:2012-10-22 14:53:59
【问题描述】:

我想为我的所有按钮添加内边距,因此我将 UIButton 子类化,并且在其他更改中,我想通过使用 setFrame 方法添加一个固定内边距。一切正常,除了 setFrame。我检查了一下,发现如果我取消选中该视图上的“使用 AutoLayout”,那么我可以使用 setFrame,它可以工作。有没有解决的办法?我真的很想使用自动布局,因为它有助于使应用程序在 iphone 5 和更早的设备上看起来都不错。但我也想在我的子类中使用 setFrame,让我的生活更轻松。

总结一下,我的问题是:我可以使用自动布局并以编程方式调整 UIView 的框架吗?

【问题讨论】:

    标签: iphone cocoa-touch interface-builder frame autolayout


    【解决方案1】:

    是的,这是可以做到的。

    如果您设置视图的translatesAutoresizingMaskIntoConstraints = YES,则对setFrame: 的调用会在运行时自动转换为基于视图当前autoresizingMask 的布局约束。这让您可以混合使用基于框架的布局和基于约束的布局。

    例如,您可以使用自动布局来定义视图的所有子视图的布局,但仍然调用setFrame: 来设置视图本身的大小和位置。从您的角度来看,您正在使用自动布局和直接框架操作混合进行布局。但系统实际上是使用约束来处理所有事情。

    但是,使用translatesAutoresizingMaskIntoConstraints 有一个很大的警告。

    当你这样做时,你仍然需要确保这些自动约束可以满足你的其余约束

    因此,例如,假设已经存在确定视图大小和位置的约束,然后您设置translatesAutoresizingMaskIntoConstraints = YES 并调用setFrame:。对setFrame: 的调用将在视图上生成新的约束,这可能会与已经存在的约束发生冲突。

    (事实上,这个错误经常发生。如果您曾经看到一条日志消息抱怨约束冲突,并且其中一个约束是NSAutoresizingMaskLayoutConstraint,那么您看到的是与自动约束的冲突。这个是一个容易犯的错误,因为translatesAutoresizingMaskIntoConstraints = YES 是默认值,所以如果您在代码中配置约束,如果您不想要这些自动约束,则需要记住将其关闭。)

    相反,再次假设已经存在确定视图大小和位置的约束,但是在调用setFrame: 之前设置了translatesAutoresizingMaskIntoConstraints = NO。在这种情况下,您的setFrame: 调用不会产生新的约束,因此单独的约束之间不会发生冲突。但是,在这种情况下,约束和您设置的帧值之间仍然存在“冲突”。下次调用 Auto Layout 时,它会看到视图上已经存在的约束,计算它们需要的框架值,并将框架设置为本身所需的值,从而破坏您手动设置的值。

    有关更多详细信息,请查看 Apple 的 Cocoa Auto Layout Guide 中的“采用自动布局”部分。

    【讨论】:

    • 这可行,但我在日志中看到很多警告。任何人都可以建议使用这种方法的正确方法是什么?还是我应该忽略警告?谢谢
    • 如果您看到关于不可满足约束的警告,这些可能是有意义的。如果您在视图上使用translatedAutoresizingMaskIntoConstraints=true 操作时看到它们,那么可能发生的情况是您已经有一些限制(可能在 IB 中设置)试图控制该视图的框架。框架上的那些旧约束与自动调整大小掩码自动生成的约束相互作用。在这种情况下,答案是消除那些旧的约束。如果您在 IB 中添加它们只是为了让 IB 在设计时关闭,您可以将它们设置为“占位符”以丢失它们。
    • @algal 如何摆脱“旧”约束?并且让子视图只监听 setFrame: 值,这样它们两个就不会冲突了。
    • 这仍然适用于 iOS 10 吗?我正在尝试为自定义容器 VC 中的子 VC 执行此操作,但它不尊重我设置的框架。
    • 我注意到,如果您这样做,在许多情况下,您会希望从 的其他视图的框架中派生出框架的 CGRects > 使用自动布局。在这种情况下,您需要其他视图完成其自动布局传递之后执行框架计算。在视图控制器中viewDidLayoutSubviews 是这个地方。在自定义视图中应使用layoutSubviews。在这两种情况下,您都应该将帧计算放在 super 调用之后。可能值得将此添加到答案中,但我希望无论如何这是一个有用的评论!
    【解决方案2】:

    对我来说最简单的事情是从其父视图中删除我想要移动/调整大小的视图,设置其frame,然后将其添加回来。例如,在 UITableViewCell 子类中使用自定义 UILabel

    [cell.myLabel removeFromSuperview];
    cell.myLabel.frame = someFrameIGenerated;
    [cell.contentView addSubview:cell.myLabel];
    

    【讨论】:

    • 没问题。虽然我觉得有义务告诉你我最终摆脱了这个并真正学习了如何在 IB 中使用约束。我不知道它们存在,现在制作复杂的布局似乎更加合理。
    • 是的,我试过了,但无法在表头视图上获得约束。也许我应该再试一次。
    • 通过这样做,您可以消除可能会搞砸其他事情的约束。累了。
    【解决方案3】:

    对我有用的方法是简单地将IBOutlet 添加到视图控制器中作为我的约束,然后更改插座上的constant 属性。

    例如,要更改视图的 x 原点,请设置从该视图的前导约束到控制器的出口。换句话说,创建一个插座@IBOutlet var labelXOrigin: NSLayoutConstraint!。然后,当您想调整 x 位置时,只需执行类似

    的操作
    self.labelXOrigin.constant = 20.0 // Or whatever origin you want to set.
    

    【讨论】:

      【解决方案4】:

      设置子视图框架的最佳方法是 viewWillLayoutSubviews 方法 自动布局项目。

      设置属性 translateAutoresizingMaskIntoConstraints = true this 将在视图确实出现或在按钮上设置选项卡后工作,就在之后 视图确实出现了。

      【讨论】:

        【解决方案5】:

        如果您的应用不支持多种设备方向。

        viewDidLoad 中设置要调整大小的视图的框架

        - (void)viewDidLoad
        {
            [super viewDidLoad];
            // Do any additional setup after loading the view.
            [aView setFrame:CGRectMake(15, 15, 100, 100)];
        }
        

        然后在viewDidLayoutSubviews中:

        -(void)viewDidLayoutSubviews
        {
            [self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
        }
        

        我不确定,但我认为如果您使用此解决方案,将一个方向切换到另一个方向可能会导致问题

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-20
          • 1970-01-01
          • 1970-01-01
          • 2016-03-26
          • 1970-01-01
          • 1970-01-01
          • 2011-12-08
          相关资源
          最近更新 更多