获取以编程方式创建的子视图的框架
Posted
技术标签:
【中文标题】获取以编程方式创建的子视图的框架【英文标题】:Getting frame of programmatically created subviews 【发布时间】:2015-10-15 16:04:39 【问题描述】:我有一个以编程方式创建的子视图view1
。我正在向其中添加一些UIButtons
,但这些按钮的尺寸取决于view1.frame.height
。但是,我似乎只能得到viewDidAppear
中的值,这显然不是我想要的。此外,如果我将addButtons()
函数放入viewDidLayoutSubviews
,我会得到一个无限循环。将addButtons()
放入各种UIViewController函数的结果如下(在cmets中):
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
【问题讨论】:
“但显然不是我想要的” .... 你还想要它在哪里? 【参考方案1】:每次您向视图添加按钮时,系统都会调用 viewDidLayoutSubviews,您会不断添加按钮,并且系统会不断调用 viewDidLayoutSubviews。你应该在 viewDidLoad() 时添加你的按钮。 要匹配视图的高度,您可以:
将所有按钮固定到视图的尾部和前沿 将第一个按钮的顶部固定在视图的顶部边缘 将最后一个按钮的底部固定在视图的底部 将每个按钮的顶部与前一个按钮的底部边缘固定在一起(假设不是第一个按钮) 将所有按钮的 .Height 约束为与视图的 .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)
更新(相等的水平间距)
好的,根据您的评论,我知道您还需要按钮之间的间距以及父容器的侧边相等。完整的工作视图控制器类在哪里:
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)
【讨论】:
感谢您的回答!但我试图将按钮的高度设置为它们超级视图高度的 60%,这就是为什么我需要先获取它们的超级视图的框架。viewDidLoad()
有没有办法做到这一点?
啊-好的,您可以将视图的 .Height 与 0.6 的乘数匹配,而不是将 .Height 与以前匹配-我编辑了我的答案。
非常感谢!我实际上还有一个问题:在我的原始代码中,我用它来计算每个按钮之间的距离:let distance = (view1.frame.width - buttonSide * 7) / 8.0
。有没有办法在不调用 view1.frame
的情况下做到这一点?
@user245954 我很难想象你想要实现的布局,你能快速发布你想要的布局图像吗?
是的,这是我发布的question,第一个答案解决了按钮本身之间的相等(水平)间距,但我想要的是按钮和容器视图之间的相等间距(领先和后缘)。以上是关于获取以编程方式创建的子视图的框架的主要内容,如果未能解决你的问题,请参考以下文章
当内部按钮触摸时,如何从 Superview 中删除以编程方式创建的子视图?