首页 > 解决方案 > 堆栈视图内的布局约束(以编程方式快速)

问题描述

我正在尝试为我的应用程序创建一个关于页面,但我正在努力解决我以编程方式添加的约束。我还在学习整个概念。

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

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 件事

图片1 图2

  1. 我想将大房子图标放在中心,但我不确定如何,因为我的 stackview 的对齐是领先的。

  2. 我使链接之间的间距变大,以便可以看到较长的文本,所以我的问题是如何将内部堆栈视图的大小设置为取决于包含文本的高度。

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

  4. 我想在stackview中的链接(带有闪电图标的链接)中添加点击手势,如果可能的话,我想用闭包来做到这一点。如果关闭不是为此,您能否帮助我或建议其他解决方案。我像这样尝试过,但这对我不起作用链接

先感谢您。

标签: iosswiftconstraints

解决方案


仅供参考,您应该尝试一次只解决一个问题 - 或者至少只解决相关问题(换句话说,#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
    }

}

结果:

在此处输入图像描述

在此处输入图像描述


推荐阅读