提问人:Avi Sasson 提问时间:8/15/2023 更新时间:11/13/2023 访问量:45
使 UIView 垂直拉伸到一定边距
Make UIView stretch vertically until a certain margin
问:
我有一个内容可能垂直溢出的地方,我设置了一个垂直约束(高度约束,但顶部/底部约束具有相同的效果)以防止整个视图(弹出窗口)溢出。UIView
我的目标是让视图占据其内容所需的高度,直到它从屏幕边缘(安全区域)进入预先配置的顶部和底部边距。
我的问题是,一旦我将设备旋转到横向并旋转回纵向,弹出窗口就不会像垂直那样拉伸。
我已经尝试过的事情:
- 为高度约束设置高优先级。
- 在 上设置高抗压性。
itemView
- 更新约束后调用。
layoutIfNeeded
- 创建另一个优先级较低的高度约束,告诉视图完全拉伸。
显然,这些都没有奏效。
初始状态:
旋转后:
旋转回纵向:
代码如下所示:
class PopupView: UIView, SpinnerProvider {
lazy var spinner: SNSpinnerView = {
let spinner = SNSpinnerView()
spinner.translatesAutoresizingMaskIntoConstraints = false
spinner.spinnerImageView.image = spinnerImageDefault
spinner.isHidden = false
return spinner
}()
var itemView = UIView() {
didSet {
spinner.isHidden = true
UIView.animate(withDuration: Constants.animationDuration) {
self.backgroundColor = .snDarkDimming
}
popupContainerView.addChild(itemView)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
private lazy var popupContainerView: UIView = {
let view = UIView(frame: .zero)
view.layer.cornerRadius = Constants.popUpFrameCornerRadius
view.layer.masksToBounds = true
view.accessibilityIdentifier = "popup"
return view
}()
private lazy var containerHeightConstraint: NSLayoutConstraint = {
// Constant will change.
popupContainerView.heightAnchor.constraint(lessThanOrEqualToConstant: 0)
}()
private lazy var containerLeadingConstraint: NSLayoutConstraint = {
popupContainerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor)
}()
private lazy var containerTrailingConstraint: NSLayoutConstraint = {
popupContainerView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor)
}()
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
backgroundColor = .snLoadingViewBackground
useAutoLayout()
addSubview(popupContainerView)
popupContainerView.useAutoLayout()
.center(in: self)
addSubview(spinner)
spinner.useAutoLayout()
.center(in: self)
spinner.startRotationAnimation()
NSLayoutConstraint.activate([
containerHeightConstraint,
containerLeadingConstraint,
containerTrailingConstraint
])
adjustConstraints()
}
func adjustConstraints() {
if UIDevice.current.orientation.isPortrait {
containerLeadingConstraint.constant = Constants.Portrait.leadingInset
containerTrailingConstraint.constant = Constants.Portrait.trailingInset
containerHeightConstraint.constant = UIScreen.main.bounds.height - safeAreaLayoutGuide.layoutFrame.height - (Constants.Portrait.horizontalInset * 2)
} else {
containerLeadingConstraint.constant = Constants.Landscape.leadingInset
containerTrailingConstraint.constant = Constants.Landscape.trailingInset
containerHeightConstraint.constant = UIScreen.main.bounds.height - (Constants.Landscape.horizontalInset * 2)
}
}
}
adjustConstraints
从父视图调用:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
popupView.adjustConstraints()
}
答:
0赞
deniz
11/13/2023
#1
以模态方式呈现的视图基本上受到约束。我在这里回答了类似的问题。由于布局引擎受到约束,因此在初始加载期间以一种方式求解布局,然后在返回纵向模式时以另一种方式求解布局。当视图受到约束或模棱两可时,就会发生这种情况。
如果你适当地约束你的观点,那么你就不会有这个问题。我复制了您的视图,其中包含一组正确的约束和 UIStackView 的战略性使用。请参阅以下结果:
完整的解决方案真的很长,所以我只会发布最相关的部分。
- 我首先创建了一个带有圆角和白色背景的 UIView。我称之为容器视图。我将此容器视图作为唯一的子视图添加到视图控制器的视图中。
- 然后,此容器视图还有一个子视图:UIStackView,周围有一些填充。
- 然后,我在这个 StackView 中嵌入了其他所有内容。在此示例中,我从上到下有 UILabel、UITexView、UIButton、UIButton、UIButton。
- 确保 StackView 中的标题标签 (RITM0010007) 具有固定高度。在我的示例中,我将此高度定义为 45 磅。
- 如果使用 UITextView 作为主要内容,请确保它不可滚动。可以使用 UITextView 或 UILabel 作为主要内容。不要对此定义任何约束。
- 确保堆栈视图中的按钮也定义了高度。我有 36 分。
- 确保 Stackview 的对齐方式为填充。
- Stackview 负责处理其余缺失的约束。
以下是在代码中创建容器视图的方式:
private func configureContainerView() {
//containerView is declared at the view controller level
containerView = UIView()
containerView.backgroundColor = .systemBackground
containerView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMaxXMinYCorner]
containerView.layer.cornerRadius = 12
containerView.layer.borderColor = UIColor.black.cgColor
containerView.layer.borderWidth = 1
containerView.clipsToBounds = true
containerView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(containerView)
NSLayoutConstraint.activate([
containerView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 20),
containerView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -20),
containerView.topAnchor.constraint(greaterThanOrEqualTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 20),
containerView.bottomAnchor.constraint(lessThanOrEqualTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
containerView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor)
])
}
这是在代码中创建堆栈视图的方式:
private func configureStackView() {
//primaryStackView is declared at the view controller level
primaryStackView = UIStackView()
primaryStackView.axis = .vertical
primaryStackView.spacing = 16
primaryStackView.alignment = .fill
primaryStackView.translatesAutoresizingMaskIntoConstraints = false
self.containerView.addSubview(primaryStackView)
NSLayoutConstraint.activate([
primaryStackView.leadingAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.leadingAnchor, constant: 20),
primaryStackView.trailingAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.trailingAnchor, constant: -20),
primaryStackView.topAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.topAnchor, constant: 20),
primaryStackView.bottomAnchor.constraint(equalTo: containerView.safeAreaLayoutGuide.bottomAnchor, constant: -20)
])
}
确保将其余内容添加到堆栈视图中,如下所示:
private func configureTitleView() {
let titleLabel = UILabel()
//configure title label
primaryStackView.addArrangedSubview(titleLabel)
NSLayoutConstraint.activate([
titleLabel.heightAnchor.constraint(equalToConstant: 45)
])
}
评论
UIScreen.main.bounds
adjustConstraints()
size
viewWillTransition()
UIDevice.current.orientation.isPortrait