UIStackView, упорядочивайте подвиды только тогда, когда они подходят - PullRequest
0 голосов
/ 17 июня 2020

У меня есть массив UIButton, который я пытаюсь добавить в горизонтальный UIStackView. Количество этих кнопок - динамическое c, и они могут стать настолько высокими, что не поместятся на экране.

Для моего варианта использования я хотел бы добавить кнопки слева от моего представления стека, в то время как они помещаются на экране. Итак, если у меня есть 10 кнопок, и после добавления 5-й не будет достаточно места для добавления 6-й кнопки, я хотел бы остановиться на этом моменте.

Кто-нибудь знает хороший подход для получения такого поведения ?

Мой текущий код выглядит примерно так:

import UIKit

class ViewController: UIViewController {

    let items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven"]

    override func viewDidLoad() {
        super.viewDidLoad()

        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.spacing = 5
        view.addSubview(stackView)

        for title in items {
            let button = UIButton()
            button.backgroundColor = .red
            button.setTitle(title, for: .normal)

            // if button.doesNotFit() {
            //     break
            // }

            stackView.addArrangedSubview(button)
        }

        let spacerView = UIView()
        spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal)
        stackView.addArrangedSubview(spacerView)

        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }
}

При этом я получаю следующий результат. Проблема в кнопках «Девять», «Десятка» и т. Д. c ... потому что они не подходят. Я бы не хотел, чтобы они добавлялись в UIStackView.

enter image description here

1 Ответ

1 голос
/ 17 июня 2020

Что вам нужно сделать ...

  • в viewDidLoad ()
    • создать кнопки и добавить их в массив
  • in viewDidLayoutSubviews() (чтобы у нас была допустимая ширина представления)
    • получить доступную ширину
    • очистить все существующие кнопки из представления стека
    • l oop через массив кнопок, добавив ширину кнопки + интервал
    • , если ширина меньше доступной ширины, добавьте кнопку в представление стека

Вот полный пример. Я включил параметры .left, .right и .justified:

// ButtonsAlignment is
//  left      = buttons will be left-aligned with fixed spacing
//  right     = buttons will be right-aligned with fixed spacing
//  justified = buttons will be justified edge to edge with equal spacing
enum ButtonsAlignment {
    case left
    case right
    case justified
}

class StackSpacingViewController: UIViewController {

    let items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven"]

    // array to hold your buttons
    var buttonsArray: [UIButton] = []

    // change to .left, .right, .justified to see the difference
    let spacingMode: ButtonsAlignment = .left

    // if mode is .justified, this will be the minimum spacing
    let buttonSpacing: CGFloat = 5.0

    // need to track when the view width changes (when auto-layout has set it)
    //  for use in viewDidLayoutSubviews()
    var viewWidth: CGFloat = 0.0

    // we'll need to refrence the stack view in multiple places,
    //  so don't make it local to viewDidLoad()
    let stackView = UIStackView()

    override func viewDidLoad() {
        super.viewDidLoad()

        stackView.axis = .horizontal

        if spacingMode == .left || spacingMode == .right {
            stackView.distribution = .fill
            stackView.spacing = buttonSpacing
        } else {
            stackView.distribution = .equalSpacing
        }

        view.addSubview(stackView)

        for title in items {
            let button = UIButton()
            button.backgroundColor = .red
            button.setTitle(title, for: .normal)

            // append it to the buttonsArray
            buttonsArray.append(button)
        }

        stackView.translatesAutoresizingMaskIntoConstraints = false

        stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true

        if spacingMode == .left || spacingMode == .justified {
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        }

        if spacingMode == .right || spacingMode == .justified {
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        }

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // this can (likely will) be called multiple times
        //  so only update the buttons stack view when the
        //  view's width changes
        if viewWidth != view.frame.width {
            let w = view.frame.width
            viewWidth = w
            // clear any buttons already in the stack
            stackView.subviews.forEach {
                $0.removeFromSuperview()
            }
            var curWidth: CGFloat = 0.0
            for btn in buttonsArray {
                curWidth += btn.intrinsicContentSize.width + buttonSpacing
                if curWidth < w {
                    stackView.addArrangedSubview(btn)
                }
            }
            stackView.setNeedsLayout()
            stackView.layoutIfNeeded()
        }
    }
}

Примечание: это могло бы (вероятно, было бы) работать лучше как автономный пользовательский класс представления ... упростил бы добавьте цвет "фона", и вычисления могут быть выполнены в функции подкласса layoutSubviews().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...