我有一个以编程方式创建的子视图view1
。我正在为它添加一些UIButtons
,但这些按钮的测量结果取决于view1.frame.height
。但是,我似乎只能获得viewDidAppear
中的值,这显然不是我想要的。此外,如果我将addButtons()
函数放在viewDidLayoutSubviews
中,我会得到一个无限循环。将addButtons()
放入各种UIViewController函数的结果如下(在注释中):
override func viewDidLoad() {
super.viewDidLoad()
addView1()
}
override func viewDidLayoutSubviews(){
print(view1.frame.height) // 0.0 first time it is called, 74.0, which is right, the second time it is called, but I got into an infinite loop
//addButtons() -> infinite loop
}
override func viewWillAppear(animated: Bool) {
print(view1.frame.height) //0.0
}
override func viewDidAppear(animated: Bool) {
print(view1.frame.height) //74.0, the value I want, but obviously not where I want it
}
我的addButtons()
看起来像这样:
func addButtons(){
let mon = UIButton()
let tue = UIButton()
let wed = UIButton()
let thu = UIButton()
let fri = UIButton()
let sat = UIButton()
let sun = UIButton()
let buttonsArray = ["mon": mon, "tue": tue, "wed": wed, "thu": thu, "fri": fri, "sat": sat, "sun": sun]
let daysArray1 = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
var daysArray2 = ["mon": "M", "tue":"T", "wed": "W", "thu": "T", "fri": "F", "sat": "S", "sun": "S"]
let buttonSide = view1.frame.height * 0.6
let distance = (view1.frame.width - buttonSide * 7) / 8.0
var count = 0
for day in daysArray1{
let offSet = (buttonSide ) * CGFloat(count) + distance * CGFloat(count + 1)
let centerX = (buttonSide / 2) + offSet
buttonsArray[day]!.setTitle(daysArray2[day], forState: .Normal)
buttonsArray[day]!.translatesAutoresizingMaskIntoConstraints = false
buttonsArray[day]!.layer.cornerRadius = 5
view1.addSubview(buttonsArray[day]!)
view1.addConstraint(NSLayoutConstraint(item: buttonsArray[day]!, attribute: NSLayoutAttribute.CenterY, relatedBy: .Equal, toItem: view1, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
view1.addConstraint(NSLayoutConstraint(item: buttonsArray[day]!, attribute: NSLayoutAttribute.CenterX, relatedBy: .Equal, toItem: view1, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: centerX))
view1.addConstraint(NSLayoutConstraint(item: buttonsArray[day]!, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: buttonSide))
view1.addConstraint(NSLayoutConstraint(item: buttonsArray[day]!, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: buttonSide))
count += 1
}
答案 0 :(得分:1)
每次向视图添加按钮时,系统都会调用viewDidLayoutSubviews,您可以继续添加按钮,系统会一直调用viewDidLayoutSubviews。您应该在viewDidLoad()时添加按钮。 要匹配视图的高度,您可以:
- 将所有按钮固定到视图的尾随和前沿
- 将第一个按钮的顶部固定在视图的顶边
上- 将最后一个按钮的底部固定在视图的底部
- 使用上一个按钮的下边缘(给定不是第一个按钮)固定每个按钮的顶部
- 约束所有按钮。高度匹配视图的.Height乘以0.6
这是我使用PureLayout
所做的一个例子 let someView = UIView(frame: CGRectZero)
view.addSubview(someView)
var prev: UIButton?
for i in 0..<6 {
let button = UIButton(frame: CGRectZero)
button.setBackgroundColor(UIColor.randomColor(), forUIControlState: .Normal)
someView.addSubview(button)
button.autoPinEdgeToSuperviewEdge(.Trailing)
button.autoPinEdgeToSuperviewEdge(.Leading)
button.autoMatchDimension(.Height, toDimension: .Height, ofView: someView, withMultiplier: 0.6)
if let previous = prev {
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: previous)
} else {
button.autoPinEdgeToSuperviewEdge(.Top)
}
prev = button
}
someView.autoPinEdgeToSuperviewEdge(.Trailing)
someView.autoPinEdgeToSuperviewEdge(.Leading)
someView.autoPinEdgeToSuperviewEdge(.Top)
someView.autoSetDimension(.Height, toSize: 100)
UPDATE(等水平间距)
根据你的评论确定,我知道你还需要按钮之间的间距以及父容器的侧边。其中是一个完整的工作视图控制器类:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let wrapper = UIView(frame: CGRectZero)
view.addSubview(wrapper)
wrapper.backgroundColor = UIColor.redColor()
var previous: (button: UIButton, spacer: UIView)?
for day in ["M", "T", "W", "T", "F", "S", "S"] {
let button = UIButton(frame: CGRectZero)
let spacer = UIView(frame: CGRectZero)
button.setTitle(day, forState: .Normal)
button.backgroundColor = UIColor.grayColor()
button.translatesAutoresizingMaskIntoConstraints = false
spacer.translatesAutoresizingMaskIntoConstraints = false
wrapper.addSubview(button)
wrapper.addSubview(spacer)
//set height 60% of wrapper
wrapper.addConstraint(NSLayoutConstraint(
item: button,
attribute: .Height,
relatedBy: .Equal,
toItem: wrapper,
attribute: .Height,
multiplier: 0.6,
constant: 0))
//set width same has height
wrapper.addConstraint(NSLayoutConstraint(
item: button,
attribute: .Height,
relatedBy: .Equal,
toItem: button,
attribute: .Width,
multiplier: 1,
constant: 0))
//pin button leading with spacer trailing
wrapper.addConstraint(NSLayoutConstraint(
item: button,
attribute: .Leading,
relatedBy: .Equal,
toItem: spacer,
attribute: .Trailing,
multiplier: 1,
constant: 0))
//pin spacer trailing with button leading
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Trailing,
relatedBy: .Equal,
toItem: button,
attribute: .Leading,
multiplier: 1,
constant: 0))
//align button to center
wrapper.addConstraint(NSLayoutConstraint(
item: button,
attribute: .CenterY,
relatedBy: .Equal,
toItem: wrapper,
attribute: .CenterY,
multiplier: 1,
constant: 0))
if let previous = previous {
//pin spacer Leading with previous button trailing
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Leading,
relatedBy: .Equal,
toItem: previous.button,
attribute: .Trailing,
multiplier: 1,
constant: 0))
//pin previous button's Trailing with spacer Leading
wrapper.addConstraint(NSLayoutConstraint(
item: previous.button,
attribute: .Trailing,
relatedBy: .Equal,
toItem: spacer,
attribute: .Leading,
multiplier: 1,
constant: 0))
//set spacer's width same as previous spacer
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Width,
relatedBy: .Equal,
toItem: previous.spacer,
attribute: .Width,
multiplier: 1,
constant: 0))
} else {
//this is the first item, pin the spacer Leading to wrapper Leading
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Leading,
relatedBy: .Equal,
toItem: wrapper,
attribute: .Leading,
multiplier: 1,
constant: 0))
}
previous = (button: button, spacer: spacer)
}
// last spacer
if let previous = previous {
let spacer = UIView(frame: CGRectZero)
spacer.translatesAutoresizingMaskIntoConstraints = false
wrapper.addSubview(spacer)
//pin spacer Leading with previous button trailing
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Leading,
relatedBy: .Equal,
toItem: previous.button,
attribute: .Trailing,
multiplier: 1,
constant: 0))
//pin previous button's Trailing with spacer Leading
wrapper.addConstraint(NSLayoutConstraint(
item: previous.button,
attribute: .Trailing,
relatedBy: .Equal,
toItem: spacer,
attribute: .Leading,
multiplier: 1,
constant: 0))
//set spacer's width same as previous spacer
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Width,
relatedBy: .Equal,
toItem: previous.spacer,
attribute: .Width,
multiplier: 1,
constant: 0))
//pin spacer's Trailing with wrappper Trailing
wrapper.addConstraint(NSLayoutConstraint(
item: spacer,
attribute: .Trailing,
relatedBy: .Equal,
toItem: wrapper,
attribute: .Trailing,
multiplier: 1,
constant: 0))
}
wrapper.frame = CGRect(x: 0, y: 100, width: 320, height: 40)
}
}