ios - 代码中的 UIStackView 设置 layoutMargins 会中断对齐
问题描述
我正在尝试将 layoutMargins 添加到UIStackView
我在代码中创建的某些元素中。我在 IB 中尝试过同样的事情并且效果很好,但是当我添加layoutMargins
并设置时isLayoutMarginsRelativeArrangement = true
,我的堆栈视图的对齐会中断。
我的堆栈视图的代码如下:
@objc lazy var buttonsStackView: UIStackView = {
let stack = UIStackView(arrangedSubviews: [doneButton, separatorView, giftButton])
stack.layoutMargins = UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 4)
stack.isLayoutMarginsRelativeArrangement = true
stack.axis = .horizontal
stack.frame = CGRect(x: 0, y: 0, width: 150, height: 44)
stack.spacing = 4
stack.distribution = .equalCentering
stack.alignment = .center
let bgView = UIView(frame: stack.bounds)
stackViewBackground = bgView
bgView.backgroundColor = ColorManager.shared.grayColor
bgView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
stack.insertSubview(bgView, at: 0)
separatorView.heightAnchor.constraint(equalTo: stack.heightAnchor, multiplier: 0.8).isActive = true
return stack
}()
SeparatorView 只有 1pt 宽度约束,而两个按钮不受约束以保持它们的intrinsicContentSize
.
这是我的 stackView 的isLayoutMarginsRelativeArrangement
外观false
:
但显然,需要左右边距,所以当设置isLayoutMarginsRelativeArrangement
为时true
,我的堆栈视图的对齐中断:
不幸的是,我不能将 IB 用于这个特定的视图,我需要从代码中初始化它。非常感谢有关如何解决此问题的任何想法。谢谢!
解决方案
这是一个制作自定义视图的示例,separator
水平居中,按钮在每个“边”中居中:
protocol DoneGiftDelegate: class {
func doneButtonTapped()
func giftButtonTapped()
}
class DoneGiftView: UIView {
weak var delegate: DoneGiftDelegate?
let doneButton: UIButton = {
let v = UIButton(type: .system)
v.setTitle("Done", for: [])
v.tintColor = .white
return v
}()
let giftButton: UIButton = {
let v = UIButton(type: .system)
v.setImage(UIImage(systemName: "gift.fill"), for: [])
v.tintColor = .white
return v
}()
let separatorView: UIView = {
let v = UIView()
v.backgroundColor = .white
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = .lightGray // ColorManager.shared.grayColor
[doneButton, separatorView, giftButton].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
addSubview($0)
}
// width and height constraints: 150 x 44
// set Priority to 999 so it can be overriden by controller if desired
let widthConstraint = widthAnchor.constraint(equalToConstant: 150.0)
widthConstraint.priority = UILayoutPriority(rawValue: 999)
let heightConstraint = heightAnchor.constraint(equalToConstant: 44.0)
heightConstraint.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activate([
// doneButton Leading to Leading
doneButton.leadingAnchor.constraint(equalTo: leadingAnchor),
// separator Leading to doneButton Trailing
separatorView.leadingAnchor.constraint(equalTo: doneButton.trailingAnchor),
// giftButton Leading to separator Trailing
giftButton.leadingAnchor.constraint(equalTo: separatorView.trailingAnchor),
// giftButton Trailing to Trailing
giftButton.trailingAnchor.constraint(equalTo: trailingAnchor),
// all centered vertically
doneButton.centerYAnchor.constraint(equalTo: centerYAnchor),
separatorView.centerYAnchor.constraint(equalTo: centerYAnchor),
giftButton.centerYAnchor.constraint(equalTo: centerYAnchor),
// doneButton Height = Height
doneButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1.0),
// separator Height = 80% of Height
separatorView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.8),
// giftButton Height = Height
giftButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1.0),
// separator Width = 1
separatorView.widthAnchor.constraint(equalToConstant: 1.0),
// doneButton Width = giftButton Width
doneButton.widthAnchor.constraint(equalTo: giftButton.widthAnchor, multiplier: 1.0),
// self Width and Height
widthConstraint,
heightConstraint,
])
// add target actions for buttons
doneButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
giftButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}
@objc func buttonTapped(_ sender: UIButton) -> Void {
if sender == doneButton {
delegate?.doneButtonTapped()
} else {
delegate?.giftButtonTapped()
}
}
}
class DemoViewController: UIViewController, DoneGiftDelegate {
let doneGiftView: DoneGiftView = DoneGiftView()
let testView: UIView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
doneGiftView.translatesAutoresizingMaskIntoConstraints = false
testView.translatesAutoresizingMaskIntoConstraints = false
testView.addSubview(doneGiftView)
view.addSubview(testView)
// so we can see the view frame
testView.backgroundColor = .cyan
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// testView Top: 100
// Leading / Trailing with 20-pts "padding"
// Height: 80
testView.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
testView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
testView.heightAnchor.constraint(equalToConstant: 80.0),
// doneGiftView Trailing to testView Trailing
doneGiftView.trailingAnchor.constraint(equalTo: testView.trailingAnchor),
// doneGiftView centered vertically in testView
doneGiftView.centerYAnchor.constraint(equalTo: testView.centerYAnchor),
])
doneGiftView.delegate = self
}
func doneButtonTapped() {
print("Done button tapped!")
// do what we want when Done button tapped
}
func giftButtonTapped() {
print("Gift button tapped")
// do what we want when Gift button tapped
}
}
示例结果:
推荐阅读
- java - How to reference enum fields from within Builder of another class?
- bluetooth - BlueZ:接口“org.bluez.Network1”上带有签名“s”的方法“Connect”不存在
- c# - 统一容器解决协方差
- javascript - 将 HighCharts 的 svg 输出 POST 到内部服务器
- react-native - React Navigation v3 Modal 不适用于 createBottomTabNavigator
- python - Pandas: count gaps for specific values
- python - Django获取PointField的坐标值
- jquery - 将 div 内部的滚动匹配到另一个外部 div
- java - 重用 bean 的 XML 片段
- c# - 将可执行文件包含到 UWP 最终包中