如何修复视图居中之谜?
How to Fix View Centering Mystery?
我有一个 UIStackView,它包含一个图像视图和一个文本视图。图像视图有一个 activity 指示器视图作为子视图(我以编程方式添加)。当视图初始视图加载时,我将 activity 指示器视图置于图像视图的中心并启动 AIV 的动画。但是,在等待图像加载的过程中,如果我旋转图像视图,AIV 需要重新居中。我添加了代码来侦听状态栏方向更改通知,并有一个方法来调用通知 (UIApplicationDidChangeStatusBarOrientationNotification)。在该方法中,我尝试获取图像视图的边界并使用它在图像视图中重新居中 AIV。但是,当设备方向改变时,图像视图边界的值似乎没有改变。在设备方向改变后,是否有一种“可靠”的方法来获取视图的更新边界?代码 ->
// start listening for orientation changes
NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationDidChange:",
name: UIApplicationDidChangeStatusBarOrientationNotification, object: nil)
那么我有:
func orientationDidChange(notification: NSNotification) {
// get image view bounds
let viewBounds = _imageView.bounds
// recenter the activity indicator
_activityIndicator.center = CGPointMake(CGRectGetMidX(viewBounds), CGRectGetMidY(viewBounds))
}
更新:
所以我摆脱了上面的并尝试了这个:
// setup activity indicator
_activityIndicatorView.translatesAutoresizingMaskIntoConstraints = true
_imageView.addSubview(_activityIndicatorView)
// set constraints
let centerXConstraint = NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterX,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
_activityIndicatorView.addConstraint(centerXConstraint)
let centerYConstraint = NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterY,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterY, multiplier: 1.0,
constant: 0.0)
_activityIndicatorView.addConstraint(centerYConstraint)
这在我看来确实是load方法。控制台吐出这个:
2015-10-27 19:26:09.303 Historic Sites Navigator[373:93902] 未为约束准备视图层次结构:
添加到视图时,约束项必须是该视图(或视图本身)的后代。如果在组装视图层次结构之前需要解决约束,这将崩溃。中断 -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] 进行调试。
2015-10-27 19:26:09.308 Historic Sites Navigator[373:93902] 查看层次结构未准备好约束。
约束:
容器层次结构:
>
| >
在容器层次结构中找不到视图:>
该视图的父视图:>
2015-10-27 19:26:09.310 Historic Sites Navigator[373:93902] * 由于未捕获的异常 'NSGenericException' 而终止应用程序,原因:'无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是非法的。约束:视图:>'
* 首先抛出调用栈:
(0x2643767b 0x377b2e17 0x264375c1 0x27177983 0x2a628f85 0x2a628dd5 0x2a628cef 0x2ad33971 0x2a628bd7 0xdf6c4 0xdfe34 0x2a5271c7 0x2a526dad 0x2ad8ca09 0x2a8689ad 0x2a88c095 0x2a88e6c5 0x2a88e931 0x2a61e989 0x2a891bb7 0x2ab33085 0x2ac09b39 0x2ac09967 0x2a883d95 0xccac8 0xccc10 0x2a659487 0x2a71440b 0x2a7cc0b9 0x2a7d79eb 0x2a519ecd 0x263fa4c9 0x263f87cd 0x263f8bff 0x2634c119 0x2634bf05 0x2f502ac9 0x2a58ef15 0xd6e74 0x37f21873)
libc++abi.dylib:以 NSException
类型的未捕获异常终止
对于 iOS 8 和 9,在视图大小变化时调用以下函数(例如在界面旋转时):
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (coordinator) -> Void in
// here the new size is already set, so place your code here
}, completion: nil)
}
除此之外,您可以使用约束(自动布局)来定位 UIActivityIndicatorView。
您当前的自动布局错误是因为您必须:
- 将 translatesAutoresizingMaskIntoConstraints 设置为 false
- 将约束添加到图像视图,而不是 ai-view
观看 WWDC 2015 的自动布局视频后,我能够编写正确且有效的代码:
_activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
_imageView.addSubview(_activityIndicatorView)
NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterX,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterX, multiplier: 1.0,
constant: 0.0).active = true
NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterY,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterY, multiplier: 1.0,
constant: 0.0).active = true
@13:48 这个视频是关键:
https://developer.apple.com/videos/play/wwdc2015-219/
我有一个 UIStackView,它包含一个图像视图和一个文本视图。图像视图有一个 activity 指示器视图作为子视图(我以编程方式添加)。当视图初始视图加载时,我将 activity 指示器视图置于图像视图的中心并启动 AIV 的动画。但是,在等待图像加载的过程中,如果我旋转图像视图,AIV 需要重新居中。我添加了代码来侦听状态栏方向更改通知,并有一个方法来调用通知 (UIApplicationDidChangeStatusBarOrientationNotification)。在该方法中,我尝试获取图像视图的边界并使用它在图像视图中重新居中 AIV。但是,当设备方向改变时,图像视图边界的值似乎没有改变。在设备方向改变后,是否有一种“可靠”的方法来获取视图的更新边界?代码 ->
// start listening for orientation changes
NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationDidChange:",
name: UIApplicationDidChangeStatusBarOrientationNotification, object: nil)
那么我有:
func orientationDidChange(notification: NSNotification) {
// get image view bounds
let viewBounds = _imageView.bounds
// recenter the activity indicator
_activityIndicator.center = CGPointMake(CGRectGetMidX(viewBounds), CGRectGetMidY(viewBounds))
}
更新:
所以我摆脱了上面的并尝试了这个:
// setup activity indicator
_activityIndicatorView.translatesAutoresizingMaskIntoConstraints = true
_imageView.addSubview(_activityIndicatorView)
// set constraints
let centerXConstraint = NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterX,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
_activityIndicatorView.addConstraint(centerXConstraint)
let centerYConstraint = NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterY,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterY, multiplier: 1.0,
constant: 0.0)
_activityIndicatorView.addConstraint(centerYConstraint)
这在我看来确实是load方法。控制台吐出这个:
2015-10-27 19:26:09.303 Historic Sites Navigator[373:93902] 未为约束准备视图层次结构: 添加到视图时,约束项必须是该视图(或视图本身)的后代。如果在组装视图层次结构之前需要解决约束,这将崩溃。中断 -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] 进行调试。 2015-10-27 19:26:09.308 Historic Sites Navigator[373:93902] 查看层次结构未准备好约束。 约束: 容器层次结构: > | > 在容器层次结构中找不到视图:> 该视图的父视图:> 2015-10-27 19:26:09.310 Historic Sites Navigator[373:93902] * 由于未捕获的异常 'NSGenericException' 而终止应用程序,原因:'无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是非法的。约束:视图:>' * 首先抛出调用栈: (0x2643767b 0x377b2e17 0x264375c1 0x27177983 0x2a628f85 0x2a628dd5 0x2a628cef 0x2ad33971 0x2a628bd7 0xdf6c4 0xdfe34 0x2a5271c7 0x2a526dad 0x2ad8ca09 0x2a8689ad 0x2a88c095 0x2a88e6c5 0x2a88e931 0x2a61e989 0x2a891bb7 0x2ab33085 0x2ac09b39 0x2ac09967 0x2a883d95 0xccac8 0xccc10 0x2a659487 0x2a71440b 0x2a7cc0b9 0x2a7d79eb 0x2a519ecd 0x263fa4c9 0x263f87cd 0x263f8bff 0x2634c119 0x2634bf05 0x2f502ac9 0x2a58ef15 0xd6e74 0x37f21873) libc++abi.dylib:以 NSException
类型的未捕获异常终止对于 iOS 8 和 9,在视图大小变化时调用以下函数(例如在界面旋转时):
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (coordinator) -> Void in
// here the new size is already set, so place your code here
}, completion: nil)
}
除此之外,您可以使用约束(自动布局)来定位 UIActivityIndicatorView。
您当前的自动布局错误是因为您必须:
- 将 translatesAutoresizingMaskIntoConstraints 设置为 false
- 将约束添加到图像视图,而不是 ai-view
观看 WWDC 2015 的自动布局视频后,我能够编写正确且有效的代码:
_activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
_imageView.addSubview(_activityIndicatorView)
NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterX,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterX, multiplier: 1.0,
constant: 0.0).active = true
NSLayoutConstraint(item: _activityIndicatorView, attribute: .CenterY,
relatedBy: .Equal, toItem: _imageView,
attribute: .CenterY, multiplier: 1.0,
constant: 0.0).active = true
@13:48 这个视频是关键: https://developer.apple.com/videos/play/wwdc2015-219/