Ограничения макета внутри стека (быстро программно) - PullRequest
0 голосов
/ 02 марта 2020

Я пытаюсь создать страницу 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. Я хотел бы разместить значок большого дома в центре, но я не уверен, как, потому что выравнивание моего стека является ведущим.

  2. Я делаю интервал между ссылками большим, чтобы мой более длинный текст был виден, поэтому мой вопрос здесь состоит в том, как установить размер внутреннего стека в зависимости от высоты содержащего текста.

  3. Как вертикально расположить значок молнии и текст внутри стека просмотра?

  4. Я хотел бы добавить жест касания к своим ссылкам внутри стек (вид со значком молнии), и я хотел бы сделать это с замыканиями, если это возможно. Не могли бы вы помочь мне с этим или предложить другое решение, если закрытия не для этого. Я попробовал это так, но у меня это не получилось как-то ссылка

Заранее спасибо.

1 Ответ

0 голосов
/ 03 марта 2020

К вашему сведению, вы должны стараться придерживаться одного вопроса за раз - или, по крайней мере, только связанных вопросов (другими словами, № 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
    }

}

Результат:

enter image description here

enter image description here

...