正如 Uli 在下面评论的那样,正确的做法是覆盖 layoutSubviews
并在那里布局 imageViews。
如果由于某种原因,您不能继承和覆盖 layoutSubviews
,观察 bounds
应该可以工作,即使有点脏。更糟糕的是,观察存在风险——Apple 不保证 KVO 可以在 UIKit 类上工作。在此处阅读与 Apple 工程师的讨论:When does an associated object get released?
原答案:
您可以使用键值观察:
[yourView addObserver:self forKeyPath:@"bounds" options:0 context:nil];
并实施:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == yourView && [keyPath isEqualToString:@"bounds"]) {
// do your stuff, or better schedule to run later using performSelector:withObject:afterDuration:
}
}
在 UIView
子类中,可以使用 属性观察者:
override var bounds: CGRect {
didSet {
// ...
}
}
如果没有子类化,使用智能键路径的键值观察将可以:
var boundsObservation: NSKeyValueObservation?
func beginObservingBounds() {
boundsObservation = observe(\.bounds) { capturedSelf, _ in
// ...
}
}
frame
是派生和运行时计算的属性。不要覆盖这个,除非你有一个非常聪明和知道的理由这样做。否则:使用 bounds
或(甚至更好)layoutSubviews
。
override var bounds: CGRect { didSet { layer.cornerRadius = bounds.size.width / 2 }}
创建 UIView 的子类,并覆盖 layoutSubviews
Swift 4 keypath KVO——这就是我检测自动旋转并移动到 iPad 侧面板的方式。应该工作任何视图。必须观察 UIView 的层。
private var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observer = view.layer.observe(\.bounds) { object, _ in
print(object.bounds)
}
// ...
}
override func viewWillDisappear(_ animated: Bool) {
observer?.invalidate()
//...
}
.layer
成功了!你知道为什么使用 view.observe
不起作用吗?
您可以创建 UIView 的子类并覆盖
setFrame:(CGRect)帧
方法。这是当视图的框架(即大小)发生变化时调用的方法。做这样的事情:
- (void) setFrame:(CGRect)frame
{
// Call the parent class to move the view
[super setFrame:frame];
// Do your custom code here.
}
UITextView
子类中,由于自动旋转导致调整大小时,setFrame:
未被调用,而 layoutSubviews:
被调用。注意:我正在使用自动布局 & iOS 7.0。
setFrame:
。 frame
是派生属性。看我的回答
很老,但仍然是一个好问题。在 Apple 的示例代码和他们的一些私有 UIView 子类中,他们重写 setBounds 大致如下:
-(void)setBounds:(CGRect)newBounds {
BOOL const isResize = !CGSizeEqualToSize(newBounds.size, self.bounds.size);
if (isResize) [self prepareToResizeTo:newBounds.size]; // probably saves
[super setBounds:newBounds];
if (isResize) [self recoverFromResizing];
}
覆盖 setFrame:
不是一个好主意。 frame
派生自 center
、bounds
和 transform
,因此 iOS 不一定会调用 setFrame:
。
setBounds:
(至少在 iOS 7.1 上)。这可能是 Apple 为避免附加消息而添加的优化。
frame
和 bounds
都派生自视图的底层 CALayer
;他们只是调用层的吸气剂。 setFrame:
设置图层的框架,而 setBounds:
设置图层边界。因此,您不能只覆盖其中一个。此外,layoutSubviews
被过度调用(不仅仅是几何变化),因此它也可能并不总是一个好的选择。还在寻找...
如果您在 UIViewController 实例中,则覆盖 viewDidLayoutSubviews
可以解决问题。
override func viewDidLayoutSubviews() {
// update subviews
}
UIView
实例和 UIViewController
实例之间的关系。因此,如果您有一个没有附加 VC 的 UIView
实例,其他答案很好,但如果您碰巧附加到 VC,这就是您的人选。抱歉,它不适用于您的情况。
不定期副业成功案例分享
viewWillTransition
等等。layoutSubviews
方法?