尝试以编程方式使用嵌套的 Stack 视图制作网格
Posted
技术标签:
【中文标题】尝试以编程方式使用嵌套的 Stack 视图制作网格【英文标题】:Trying to make a grid with nested UIStack views programatically 【发布时间】:2018-04-17 19:11:48 【问题描述】:我想创建始终适合其父视图大小的“GridView”。所以我的想法是这样的:
将垂直堆栈视图作为主容器。 在垂直堆栈视图内将是水平堆栈视图行。 作为补充,我只想在水平堆栈视图的行中添加按钮。所以关于如何初始化它的一般纲要如下:
-
初始化垂直堆栈视图并将其约束设置为其父视图的前导、尾随、宽度和高度锚点。
根据给定的网格尺寸 (AxB),在这些水平行内创建 A 水平堆栈行和 B 按钮。
将每个水平堆栈的约束设置为等于其父视图的前导、尾随、宽度和高度(主容器堆栈视图)。
将每个按钮的 autoresizingMask 设置为 flexibleWidth 和 flexibleHeight。
这是我目前用于初始化“GridView”的当前逻辑,我正在使用它来实现我的实现。现在我遇到的主要问题是水平堆栈视图不是垂直堆叠,而是实际上最终只是相互重叠。
(1x1) Overlap
如果我将按钮 just 添加到主容器中,它将垂直堆叠而不会出现问题。
(1x1) Vertical Buttons
似乎将水平堆栈放入垂直堆栈会导致问题。有什么想法和建议吗?我曾想过只使用表格视图来创建网格,但这个问题让我很好奇,我真的很想知道为什么会这样。
这是我的代码实现:
func createGrid(x: Int, y: Int, rootView: UIView)
//Init stack view.
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fillEqually
for i in (1...x)
let hStackView = UIStackView()
hStackView.axis = .horizontal
hStackView.alignment = .fill
hStackView.distribution = .fillEqually
for _ in (1...y)
let button = WordBoxView()
button.setTitle("\(i)", for: .normal)
hStackView.addArrangedSubview(button)
let button = WordBoxView()
button.setTitle("\(i)", for:.normal)
hStackView.addArrangedSubview(button)
//Add horizontal row stack to vertical parent stack.
stackView.addSubview(hStackView)
fitParentLayout(hStackView, parentView: stackView)
rootView.addSubview(stackView)
//setup stack view bounds
stackView.translatesAutoresizingMaskIntoConstraints = false
fitParentLayout(stackView, parentView: rootView)
func fitParentLayout(_ child: UIView, parentView: UIView)
child.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
parentView.leadingAnchor.constraint(equalTo: child.leadingAnchor),
parentView.trailingAnchor.constraint(equalTo: child.trailingAnchor),
parentView.widthAnchor.constraint(equalTo: child.widthAnchor),
parentView.heightAnchor.constraint(equalTo: child.heightAnchor)])
【问题讨论】:
我认为你可以用集合视图来做到这一点,你试过了吗? 你真的不应该使用addSubview
添加UIStackView
子视图,即使用addArrangedSubview
添加hStackView
到垂直堆栈视图。另外,不要添加约束(无需使用fitParentLayout
将水平堆栈视图添加到垂直堆栈视图)。
【参考方案1】:
我在您的代码中发现了 2 个问题:
您已添加
leading, trailing, width
和height
约束,但它不会确定您的视图的y 原点。所以分配top
。 (前导和尾随将自动确定宽度,因此无需给出宽度限制)你只需要给外部
UIStackView
一个约束,内部堆栈视图会根据外部堆栈视图的属性自动获取帧。
将您的代码更新为:
func createGrid(x: Int, y: Int, rootView: UIView)
//Init stack view.
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.distribution = .fillEqually
stackView.spacing = 10
for i in 1...x
let hStackView = UIStackView()
hStackView.axis = .horizontal
hStackView.alignment = .fill
hStackView.distribution = .fillEqually
hStackView.spacing = 10
for _ in 1...y
let button = UIButton()
button.backgroundColor = .red
button.setTitle("\(i)", for: .normal)
hStackView.addArrangedSubview(button)
//Add horizontal row stack to vertical parent stack.
stackView.addArrangedSubview(hStackView)
rootView.addSubview(stackView)
//setup stack view bounds
fitParentLayout(stackView, parentView: rootView)
func fitParentLayout(_ child: UIView, parentView: UIView)
child.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
parentView.leadingAnchor.constraint(equalTo: child.leadingAnchor),
parentView.trailingAnchor.constraint(equalTo: child.trailingAnchor),
parentView.topAnchor.constraint(equalTo: child.topAnchor),
parentView.heightAnchor.constraint(equalTo: child.heightAnchor)])
【讨论】:
这行得通,在 fitParentLayout() 而不是 parentView.heightAnchor.constraint(equalTo: child.heightAnchor)]) 我使用了 parentView.bottomAnchor.constraint(equalTo: child.bottomAnchor)])。跨度> 【参考方案2】:你说
将每个水平堆栈的约束设置为其父视图(主容器堆栈视图)的前导、尾随、宽度和高度。
您不希望行(水平堆栈视图)的高度等于主容器堆栈视图的高度。设置高度限制可能是你的麻烦的原因。
移除此约束:
parentView.heightAnchor.constraint(equalTo: child.heightAnchor)
您也不需要父/子宽度限制,但那是无害的。
【讨论】:
你是对的,我使用了错误的约束,我没有意识到这一点。我调整了我的代码以匹配@DonMag 的建议。【参考方案3】:几个“哎呀”错误......
在for i in (1...x)
循环结束时:
//Add horizontal row stack to vertical parent stack.
stackView.addSubview(hStackView)
应该是:
//Add horizontal row stack to vertical parent stack.
stackView.addArrangedSubview(hStackView)
而且,您不需要(也不应该这样做)以下行
fitParentLayout(hStackView, parentView: stackView)
因为您正在使用垂直堆栈视图的.alignment
和.distribution
来控制子水平堆栈视图的大小/位置。
而且,您的fitParentLayout()
已交换视图。应该是:
func fitParentLayout(_ child:UIView, parentView:UIView)
child.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
child.trailingAnchor.constraint(equalTo: parentView.trailingAnchor),
child.topAnchor.constraint(equalTo: parentView.topAnchor),
child.bottomAnchor.constraint(equalTo: parentView.bottomAnchor)])
应该可以的。
【讨论】:
啊,我应该一直使用 topAnchor 和 bottomAnchor 而不是宽度和高度锚约束。以上是关于尝试以编程方式使用嵌套的 Stack 视图制作网格的主要内容,如果未能解决你的问题,请参考以下文章
嵌套堆栈视图:以编程方式附加子堆栈视图时,子堆栈视图不在其父堆栈视图内
Android 编程:如何以网格方式以编程方式创建各种视图类型