堆栈视图内的布局约束(以编程方式快速)
Posted
技术标签:
【中文标题】堆栈视图内的布局约束(以编程方式快速)【英文标题】:Layout constraints inside a stackview (swift programmatically) 【发布时间】:2020-03-02 20:05:21 【问题描述】:我正在尝试为我的应用创建一个关于页面,但我正在努力解决我以编程方式添加的限制。我还在学习整个概念。
这是我的代码,我复制到游乐场
import UIKit
import PlaygroundSupport
class TestViewController: UIViewController
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
override func viewDidLoad()
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
self.stackView.alignment = UIStackView.Alignment.leading
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
//constrain width of stack view to width of self.view, NOT scroll view
self.stackView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true;
//Text Label
aboutText.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
aboutText.append("Maecenas sed pulvinar est. Integer mattis mollis eleifend. Integer suscipit arcu sit amet erat rhoncus malesuada. Nam feugiat augue id leo maximus dignissim id sed libero. Proin dapibus metus vel nisl ultrices, quis laoreet metus malesuada. Lorem ipsum dolor sit amet, consectetur adipiscing elit. ")
aboutText.append(" penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sit amet dui consectetur, vulputate felis sed, volutpat dui. Quisque eu ex eu nulla facilisis aliquet. Vestibulum vitae lacus non sapien posuere commodo et eget arcu. Sed quis eros condimentum, pharetra ligula non, gravida ex. Cras luctus com")
aboutText.append(" Praesent luctus nulla eget condimentum volutpat. Nunc metus odio, commodo sit amet placerat non, cursus posuere sem. Mauris lorem felis, elementum vel purus")
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
let image = UIImage(systemName: "house")
let imageView = UIImageView(image: image!)
imageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 60).isActive = true
stackView.addArrangedSubview(imageView)
for text in aboutText
stackView.addArrangedSubview(generateText(text:text))
stackView.addArrangedSubview(generateStackedItem(imageName:"bell",text: "contact_us"))
stackView.addArrangedSubview(generateStackedItem(imageName:"bolt",text: "rate_us_ios"))
for link in fbLinks
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
sw.leadingAnchor.constraint(equalTo: self.stackView.leadingAnchor).isActive = true;
sw.trailingAnchor.constraint(equalTo: self.stackView.trailingAnchor).isActive = true;
func generateText(text:String)->UILabel
let textLabel = UILabel()
textLabel.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
func generateStackedItem(imageName:String,text:String)->UIStackView
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
stackView.alignment = UIStackView.Alignment.leading
stackView.spacing = 5.0
let image = UIImage(systemName: imageName)
let imageView = UIImageView(image: image!)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
let label = generateText(text: text)
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.heightAnchor.constraint(equalToConstant: label.frame.height).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
return stackView
let vc = TestViewController()
vc.view.backgroundColor = .white
PlaygroundPage.current.liveView = vc
这就是页面的样子,我标记了 3 件事
我想将大房子图标放在中间,但我 不知道怎么做,因为我的 stackview 的对齐是领先的。
我使链接之间的间距变大,以便可以看到较长的文本,所以我的问题是如何将内部堆栈视图的大小设置为取决于包含文本的高度。
如何让闪电图标和堆栈视图中的文本垂直居中?
我想在 stackview 中的链接(带有闪电图标的链接)中添加点击手势,如果可能的话,我想用闭包来实现。如果关闭不是为此,您能否帮助我或建议其他解决方案。我这样尝试过,但不知何故对我不起作用link
提前谢谢你。
【问题讨论】:
【参考方案1】:仅供参考,您应该尝试一次只回答一个问题 - 或者至少只回答相关个问题(换句话说,#4 应该是一个不同的问题) .
我将解决 1 到 3。
首先,您的代码中有一条注释:
//constrain width of stack view to width of self.view, NOT scroll view
这是错误的。您的堆栈视图宽度应限制为滚动视图宽度。否则,如果您的滚动视图没有在屏幕上一直伸展,它将水平滚动。
在您的情况下,您(似乎)将滚动视图插入前导和尾随 5 分:
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 5).isActive = true;
但是,您的 trailingAnchor 常量应该是 -5
。
一旦改正...
1) 将您的“主”stackView 的.alignment
也更改为.fill
而不是.leading
,并确保您的图像视图具有.contentMode = .scaleAspectFit
。这将使“房子”水平居中。
2) 您可以限制“内部堆栈视图”相对于标签高度的高度。只需确保添加该约束在将标签添加为排列的子视图
3)要使图标垂直居中 -> 标签,请将.alignment = .center
设置为水平堆栈视图。
这是您发布的代码的略微修改版本:
class TestViewController: UIViewController
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
override func viewDidLoad()
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
// trailing constant should be negative
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
// change to .fill
self.stackView.alignment = UIStackView.Alignment.leading
self.stackView.alignment = .fill
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
//constrain width of stack view to width of self.view, NOT scroll view
//self.stackView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true;
// you SHOULD constrain the stackView width to the width of the scrollView (assuming you do not want horizontal scrolling)
self.stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true;
//Text Label
aboutText.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
aboutText.append("Maecenas sed pulvinar est. Integer mattis mollis eleifend. Integer suscipit arcu sit amet erat rhoncus malesuada. Nam feugiat augue id leo maximus dignissim id sed libero. Proin dapibus metus vel nisl ultrices, quis laoreet metus malesuada. Lorem ipsum dolor sit amet, consectetur adipiscing elit. ")
aboutText.append(" penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sit amet dui consectetur, vulputate felis sed, volutpat dui. Quisque eu ex eu nulla facilisis aliquet. Vestibulum vitae lacus non sapien posuere commodo et eget arcu. Sed quis eros condimentum, pharetra ligula non, gravida ex. Cras luctus com")
aboutText.append(" Praesent luctus nulla eget condimentum volutpat. Nunc metus odio, commodo sit amet placerat non, cursus posuere sem. Mauris lorem felis, elementum vel purus")
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
let image = UIImage(systemName: "house")
let imageView = UIImageView(image: image!)
imageView.contentMode = .scaleAspectFit
imageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
stackView.addArrangedSubview(imageView)
for text in aboutText
stackView.addArrangedSubview(generateText(text:text))
stackView.addArrangedSubview(generateStackedItem(imageName:"bell",text: "contact_us"))
stackView.addArrangedSubview(generateStackedItem(imageName:"bolt",text: "rate_us_ios"))
for link in fbLinks
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
// next two lines are not needed
//sw.leadingAnchor.constraint(equalTo: self.stackView.leadingAnchor).isActive = true;
//sw.trailingAnchor.constraint(equalTo: self.stackView.trailingAnchor).isActive = true;
func generateText(text:String)->UILabel
let textLabel = UILabel()
// no need to set widthAnchor
//textLabel.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
func generateStackedItem(imageName:String,text:String)->UIStackView
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
// horizontal stack view alignment defines the Vertical alignment
//stackView.alignment = UIStackView.Alignment.leading
// so set it to .center to get vertical centering
stackView.alignment = .center
stackView.spacing = 5.0
let image = UIImage(systemName: imageName)
let imageView = UIImageView(image: image!)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
let label = generateText(text: text)
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
// constrain stackView height to label height + constant
//stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
stackView.heightAnchor.constraint(equalTo: label.heightAnchor, constant: 16).isActive = true
return stackView
结果:
【讨论】:
谢谢@DonMag!您能否推荐一个网站或书籍或其他我可以正确学习此约束内容的东西? @Mr.J - 我总是建议从 Apple 开始:Auto Layout Guide: Understanding Auto Layout - 然后只需搜索(谷歌或任何地方)ios auto layout tutorial
。很多链接......通过几十个教程。到那时你应该有一个坚实的基础,应该能够解决任何出现的问题。以上是关于堆栈视图内的布局约束(以编程方式快速)的主要内容,如果未能解决你的问题,请参考以下文章
使用堆栈视图和自动布局创建自定义 UITableViewCell
容器视图内的 UIPageViewController 内的堆栈视图的自动布局?
Swift - StackView 和添加约束,以编程方式添加视图到堆栈 - 加载后调整单元格高度?