Answers:
正如Uli在下面评论的那样,执行此操作的正确方法是覆盖layoutSubviews
并在其中布局imageViews。
如果由于某种原因您不能继承和覆盖layoutSubviews
,则观察bounds
应该可以进行,即使是脏的。更糟糕的是,存在观察的风险-苹果公司不保证KVO可以在UIKit类上使用。在这里阅读与Apple工程师的讨论:相关对象何时发布?
原始答案:
您可以使用键值观察:
[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:
}
}
viewWillTransition
等等,等等
layoutSubviews
如果根据视图的当前大小,需要添加/删除不同的子视图并且需要添加/删除不同的约束,是否仍使用推荐的方法?
在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关键路径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)frame
方法。这是在更改视图的框架(即大小)时调用的方法。做这样的事情:
- (void) setFrame:(CGRect)frame
{
// Call the parent class to move the view
[super setFrame:frame];
// Do your custom code here.
}
setFrame:
没有调用我的UITextView
子类,而是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:
在设置frame属性时(至少在iOS 7.1上),不会调用。这可能是Apple添加的一项优化措施,以避免出现其他消息。
frame
和bounds
从该视图的基本衍生CALayer
; 他们只是调用该层的吸气剂。并setFrame:
设置图层的框架,同时setBounds:
设置图层的边界。因此,您不能仅覆盖其中一个。另外,layoutSubviews
被过度调用(不仅涉及几何更改),因此也不一定总是一个好的选择。仍在寻找...
如果您在UIViewController实例中,则可以通过重写来viewDidLayoutSubviews
实现。
override func viewDidLayoutSubviews() {
// update subviews
}
UIView
实例与UIViewController
实例之间的关系。因此,如果您有一个UIView
未连接VC 的实例,那么其他答案也不错,但是如果您恰好连接至VC,这就是您的职责。抱歉,这不适用于您的情况。