为了支持iOS 11.x及更低版本,我像提到的Enrique一样扩展了UIStackView ,但是我对其进行了修改,使其包括:
- 在布置的子视图之前添加一个空格
- 处理空间已经存在并且仅需要更新的情况
- 删除额外的空间
extension UIStackView {
func addSpacing(_ spacing: CGFloat, after arrangedSubview: UIView) {
if #available(iOS 11.0, *) {
setCustomSpacing(spacing, after: arrangedSubview)
} else {
let index = arrangedSubviews.firstIndex(of: arrangedSubview)
if let index = index, arrangedSubviews.count > (index + 1), arrangedSubviews[index + 1].accessibilityIdentifier == "spacer" {
arrangedSubviews[index + 1].updateConstraint(axis == .horizontal ? .width : .height, to: spacing)
} else {
let separatorView = UIView(frame: .zero)
separatorView.accessibilityIdentifier = "spacer"
separatorView.translatesAutoresizingMaskIntoConstraints = false
switch axis {
case .horizontal:
separatorView.widthAnchor.constraint(equalToConstant: spacing).isActive = true
case .vertical:
separatorView.heightAnchor.constraint(equalToConstant: spacing).isActive = true
@unknown default:
return
}
if let index = index {
insertArrangedSubview(separatorView, at: index + 1)
}
}
}
}
func addSpacing(_ spacing: CGFloat, before arrangedSubview: UIView) {
let index = arrangedSubviews.firstIndex(of: arrangedSubview)
if let index = index, index > 0, arrangedSubviews[index - 1].accessibilityIdentifier == "spacer" {
let previousSpacer = arrangedSubviews[index - 1]
switch axis {
case .horizontal:
previousSpacer.updateConstraint(.width, to: spacing)
case .vertical:
previousSpacer.updateConstraint(.height, to: spacing)
@unknown default: return
}
} else {
let separatorView = UIView(frame: .zero)
separatorView.accessibilityIdentifier = "spacer"
separatorView.translatesAutoresizingMaskIntoConstraints = false
switch axis {
case .horizontal:
separatorView.widthAnchor.constraint(equalToConstant: spacing).isActive = true
case .vertical:
separatorView.heightAnchor.constraint(equalToConstant: spacing).isActive = true
@unknown default:
return
}
if let index = index {
insertArrangedSubview(separatorView, at: max(index - 1, 0))
}
}
}
func removeSpacing(after arrangedSubview: UIView) {
if #available(iOS 11.0, *) {
setCustomSpacing(0, after: arrangedSubview)
} else {
if let index = arrangedSubviews.firstIndex(of: arrangedSubview), arrangedSubviews.count > (index + 1), arrangedSubviews[index + 1].accessibilityIdentifier == "spacer" {
arrangedSubviews[index + 1].removeFromStack()
}
}
}
func removeSpacing(before arrangedSubview: UIView) {
if let index = arrangedSubviews.firstIndex(of: arrangedSubview), index > 0, arrangedSubviews[index - 1].accessibilityIdentifier == "spacer" {
arrangedSubviews[index - 1].removeFromStack()
}
}
}
extension UIView {
func updateConstraint(_ attribute: NSLayoutConstraint.Attribute, to constant: CGFloat) {
for constraint in constraints {
if constraint.firstAttribute == attribute {
constraint.constant = constant
}
}
}
func removeFromStack() {
if let stack = superview as? UIStackView, stack.arrangedSubviews.contains(self) {
stack.removeArrangedSubview(self)
removeFromSuperview()
}
}
}
注意:1-根据文档:
为防止在调用堆栈的removeArrangedSubview:方法后视图出现在屏幕上,请通过调用视图的removeFromSuperview()方法将其从子视图数组中显式删除,或将视图的isHidden属性设置为true。