Stackview内的布局约束(以编程方式快速移动)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Stackview内的布局约束(以编程方式快速移动)相关的知识,希望对你有一定的参考价值。

我正在尝试为我的应用程序创建一个About页面,但我在以编程方式添加的约束中苦苦挣扎。我仍在学习整个概念。

这是我的代码,我已复制到操场上

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样的页面的样子

[picture1 picture2

  1. 我想将大房子图标放在中间,但我不知道如何,因为我的stackview的对齐方式是领先的。

  2. 我将链接之间的间距增大,以便可以看到我的较长文本,所以我的问题是如何根据所包含文本的高度来设置内部stackview的大小。

  3. 如何将闪电图标和文本垂直放置在stackview中?

  4. 我想向我的stackview中的链接(带有闪电图标的链接)添加敲击手势,如果可能的话,我希望使用闭包操作。如果不能使用闭包,可以请我帮忙,或者建议其他解决方案。我这样尝试过,但对我不起作用link

先谢谢您。

答案

FYI,您应该一次只回答一个问题-或至少只回答[[相关个问题(换句话说,#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)

可以相对于标签的高度限制“内部堆栈视图”的高度。只需确保添加该约束after将标签添加为ArrangedSubview

[[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 } }

结果:

enter image description here

enter image description here

以上是关于Stackview内的布局约束(以编程方式快速移动)的主要内容,如果未能解决你的问题,请参考以下文章

StackView 中的按钮约束(以 Swift 编程方式)

如何以编程方式快速向 UITableViewCell 内的 UIStackView 添加约束?

Swift - StackView 和添加约束,以编程方式添加视图到堆栈 - 加载后调整单元格高度?

Swift - 以编程方式刷新约束

如何以编程方式将自定义 UIView 添加到 UIScrollView 之上的 Stackview?

AutoLayout经常用到的一些布局(含StackView)