提问人:ennell 提问时间:8/15/2023 更新时间:8/16/2023 访问量:65
在子视图布局约束中使用模态视图帧大小
Using modal view frame size in subview layout constraints
问:
问题:在调整模式视图控制器的子视图大小时,使用正确的帧值来模拟视口百分比时,我遇到了一些问题。我宁愿使用布局约束而不是显式框架值来调整子视图的大小。
未正确设置模态视图控制器的帧值,最高为 (包括 )。使用所需的帧值依次调用的两个方法是 和 。到目前为止,这些似乎是我唯一可以使用的“钩子”来访问正确的帧值。viewWillAppear
viewWillLayoutSubviews
viewDidAppear
这些方法不容易使用,因为:
viewWillLayoutSubviews
被多次调用,我假设是中间帧值。多次设置相同约束会引发“自动布局”约束错误。// Multiple frame values return from viewWillLayoutSubviews {{0, 0}, {393, 783}} {{0, 0}, {393, 283.66666666666663}}
viewDidAppear
效果更好,因为它只使用最终的、所需的帧值调用一次。但是,此时视图将添加到视图层次结构中并显示在屏幕上。然后,在设置布局约束时,屏幕简介会先显示不受约束的布局,然后再显示受约束的布局。
解决方法解决方案:在激活新约束之前使用和停用旧约束,以避免约束冲突。这可以通过在第一次调用 时遍历或维护对原始约束的状态变量(强引用)来完成。这似乎不是一个干净的解决方案。viewWillLayoutSubviews
modal.view.constraints
viewWillLayoutSubviews
// Utility function to activate constraints
void setConstraints (UIView* view, NSLayoutAnchor *leading, NSLayoutAnchor *trailing, NSLayoutAnchor *top, NSLayoutAnchor *bottom,
CGFloat cLeading, CGFloat cTrailing, CGFloat cTop, CGFloat cBottom, NSArray<NSLayoutConstraint*>* __strong *constraints) {
NSArray *newConstraints = @[
[view.leadingAnchor constraintEqualToAnchor:leading constant:cLeading],
[view.trailingAnchor constraintEqualToAnchor:trailing constant:cTrailing],
[view.topAnchor constraintEqualToAnchor:top constant:cTop],
[view.bottomAnchor constraintEqualToAnchor:bottom constant:cBottom]
];
[NSLayoutConstraint deactivateConstraints:*constraints];
[NSLayoutConstraint activateConstraints:newConstraints];
*constraints = newConstraints;
}
// UIViewController "hook" with eventually correct frame value
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.recordingView setConstraints];
}
// Modal view-controller setting auto layout constraints based on layoutMarginsGuide and current modal frame values
- (void) setConstraints {
UILayoutGuide *guide = self.layoutMarginsGuide;
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
setConstraints(self.textField, guide.leadingAnchor, guide.trailingAnchor, guide.topAnchor, guide.topAnchor,
0.05*width, -0.05*width, 0.0, 0.2*height, &textFieldConstraints);
setConstraints(self.progressBar, guide.leadingAnchor, guide.trailingAnchor, self.textField.bottomAnchor, self.textField.bottomAnchor,
0.05*width, -0.05*width, 0.08*height, 0.1*height, &progressBarConstraints);
}
问题:有没有更好的方法来做到这一点,而我没有看到?还是我真的不应该使用帧值作为视口宽度/高度百分比(类似于 CSS)?
答:
由于您的问题询问的是一般方法,因此下面只是一个示例,用于在其超级视图中设置文本视图的约束。
[NSLayoutConstraint activateConstraints:@[
// Set the width as a percentage of the superview's width
[self.textView.widthAnchor constraintEqualToAnchor:self.layoutMarginsGuide.widthAnchor multiplier:0.9],
// Align in the center horizontally
[self.textView.centerXAnchor constraintEqualToAnchor:self.layoutMarginsGuide.centerXAnchor],
// Set the top
[self.textView.topAnchor constraintEqualToAnchor:self.layoutMarginsGuide.topAnchor],
// Rely on the intrinsic height of the text view or you can optionally set a specific height constraint if desired
]];
第一个约束是与您的问题最相关的约束。这显示了如何使文本视图的宽度为超视图边距布局宽度的 90%。根据需要进行调整。也许根据您的需要替换。self.layoutMarginsGuide.widthAnchor
self.widthAnchor
设置一次,你就完成了。无需更新。随着上视图宽度的变化,文本视图的宽度也会发生变化。
如果要将 、 、 或设置为视图高度或宽度的百分比,则需要使用较长的形式来创建约束。topAnchor
bottomAnchor
leadingAnchor
trailingAnchor
以下将文本视图设置为超级视图的 30%:topAnchor
bottomAnchor
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.textView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:0.3 constant:0];
然后,您需要像往常一样激活它。
评论
Invalid pairing of layout attributes.
topAnchor
heightAnchor
NSLayoutAttributeHeight
NSLayoutAttributeBottom
评论
textField
UITextView
progressBar
UIProgressView
textField
UITextView