启动Xcode,为了清楚起见,仅用9.3版通用应用程序进行构建。因此,将9.3 iPad与9.3 iPhone进行比较。构建模拟器和设备-在这两者上发行展览。
该应用程序沿所有四个方向旋转。
在典型情况下,您会执行以下操作...
@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint!
var heightFraction:CGFloat = 0.6
{
didSet
{
if ( heightFraction > maxHeight ) { heightFraction = maxHeight }
if ( heightFraction < minHeight ) { heightFraction = minHeight }
let h = view.bounds.size.height
spaceshipHeightPerScreen.constant = h * heightFraction
self.view.layoutIfNeeded() // holy! read on....
}
}
注意更改约束后的layoutIfNeeded()
。继续典型的例子,您将得到类似
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
heightFraction = (heightFraction)
// use "autolayout power" for perfection every pass.
// now that basic height/position is set,
save/load reactive positions...
position detail stuff...
}
看看...我整天都在这样做,只是碰巧使用iPhone。有趣的是,您不需要调用layoutIfNeeded。
@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint!
var heightFraction:CGFloat = 0.6
{
didSet
{
if ( heightFraction > maxHeight ) { heightFraction = maxHeight }
if ( heightFraction < minHeight ) { heightFraction = minHeight }
let h = view.bounds.size.height
spaceshipHeightPerScreen.constant = h * heightFraction
}
}
工作良好。但是,最终,我把它放在一些iPad上,..一切都破了!
每当您旋转风景/肖像时,都会出现问题。
经过一番摸索,我意识到您确实需要iPad上的layoutIfNeeded调用 。在相同的操作系统上。
确实,无论操作系统版本如何,行为都会表现出来。并且它适用于所有iPhone /所有iPad。 WTF!
@IBOutlet weak var doorHeightPerScreen: NSLayoutConstraint!
var heightFraction:CGFloat = 0.6
{
didSet
{
if ( heightFraction > maxHeight ) { heightFraction = maxHeight }
if ( heightFraction < minHeight ) { heightFraction = minHeight }
let h = view.bounds.size.height
spaceshipHeightPerScreen.constant = h * heightFraction
self.view.layoutIfNeeded() //MUST HAVE, IN IPAD CASE!!!!!!
}
}
对我来说,令人难以置信地困扰,它们的工作原理有所不同。我想知道的是,也许有某个设置可以使它们相同地工作?莫非是我的错?
两者之间是否还有其他已知的区别-还是确实“知道”有一些这样的错误?
我想不出我在任何地方都做过什么奇怪或不寻常的事情,除非整个应用程序在第一个视图中都有
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return .All }
,这是正常的,如果您想将设备倒置的话。我怀疑它的相关性。除此之外,它是一个非常“干净”的新鲜应用程序。它给了我矩阵故障的感觉-这太可怕了。
是什么原因造成的?
按照RobM的问题,初始ViewController上的SimulatedMetrics设置(“属性”选项卡)为...
该应用的总体方案:第一个场景“常规”为全屏,即设备的大小。有一个“Live”容器,它的大小相同(使用“Trailing”等/约束为零)。在Live中,有一个容器视图“Quad”,实际上它的大小也已完全调整为“Live”,因此它也是全屏的。 Quad:UIViewController展示了我描述的问题。 Quad包含位于视图周围的各种对象(图像,自定义控件等)。应用启动时,一切正常。
在设备(或类似设备)旋转时:更改约束之后(我不知道这是否相关):iPad(所有iPad)需要
layoutIfNeeded
调用,而iPhone(所有iPhone)则不需要。在模拟器和设备上,行为是相同的。另一个例子 .....
我发现了另一个令人震惊的例子。
在UICollectionView中,自定义单元格(只是简单的静态大小的单元格)。如果您碰巧要更改约束(例如说调整单元格中图标或产品拍摄的大小)。
在IPAD上,您要必须确保重新调整
layoutIfNeeded
,否则它将在单元格的首次出现时不起作用。而在IPHONE上上的行为肯定不同:如果在单元格初次出现之前,它将“为您做到这一点”。
完全怪异!
我在每个iPad和每个iPhone上都进行了测试。 (此外,异常行为正好表现在设备或模拟器上:模拟器没有区别。)
最佳答案
我无法复制您所看到的内容;很高兴看到一个完整的例子。在我的模型中,我为视图控制器配置了一个视图,该视图具有一个子视图,并带有控制子视图高度的约束。我根据视图大小在viewDidLayout
中更改了子视图高度约束。 iPhone和iPad的行为均相同,并且在任何视图上都可以调用layoutIfNeeded
来工作。
就是说,我认为一旦视图完成布局,您就在更改子视图约束-是吗?我认为更好的方法是通过 viewWillTransitionToSize:withTransitionCoordinator:
在子视图之前进行布局。
func viewWillTransitionToSize(_ size: CGSize,
withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
这样,视图层次结构的自动布局可以一次完成。仅在视图更改大小时才调用此方法,因此在第一次加载视图时将不会调用此方法。您必须在其他地方设置初始约束-因为它们取决于视图大小,也许您可以使用
viewWillAppear
。或者(可能更正确),将视图控制器的视图子类化,并覆盖
updateConstraints
。这是更改约束常量的最合适的位置。最后,在属性设置器中,永远不要调用view.layoutIfNeeded()。如果有的话,可以设置view.setNeedsLayout(),以便在下一个运行循环迭代中进行布局,并拾取可能需要表示的所有更改。
关于ios - 令人恐惧的是,layoutIfNeeded序列在iPad和iPhone上的行为有所不同。怎么修?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37624943/