Автоматическое размещение регулирует высоту UIbutton в заданном диапазоне в зависимости от доступного размера экрана - PullRequest
0 голосов
/ 27 мая 2020

Я пытаюсь использовать Autolayout (программно) для создания следующей сцены. Как видно на рисунке, высота кнопки не может быть больше 56 и меньше 44 при любом размере экрана. Верхнее представление содержимого имеет собственный размер, основанный на его внутреннем содержимом, но его верхний якорь должен иметь минимальное верхнее дополнение 8. Оно может быть больше 8. Отступ между кнопками и представлением содержимого строго 8 пунктов. а нижний отступ с нижним якорем - строгий 12. Единственное, с чем я могу поиграть, - это высота кнопки, чтобы настроить все содержимое на маленьком экране.

enter image description here

Попыток 1) Я попытался поместить все кнопки в представление стека и установил ограничение по высоте для каждого кнопок.

button.heightAnchor.constraint(lessThanOrEqualToConstant: 56).isActive = true
button.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).isActive = true

, но высота кнопки никогда не увеличивается более чем на 44. Теперь она работает правильно, когда я устанавливаю верхнее ограничение между основным видом и видом сверху с строгим 8

contentView.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true

, а не

contentView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 8).isActive = true

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

2) Когда Я не использую представление стека и устанавливаю ограничение высоты для каждой кнопки, независимо от того, какое устройство это когда-либо, оно никогда не увеличивается больше чем 44. Если я удалю ограничение больше чем 44, то размер кнопки уменьшится до 36. Я попытался установить приоритет на самое верхнее ограничение, чем 8, а также высоту ограничений кнопки, а также установить ограничение соотношения сторон между представлением содержимого и верхней кнопкой, а затем установить высоту всех остальных кнопок. t на верхнюю кнопку, но опять же, все просто застревает до 44.

Пожалуйста, посоветуйте или предложите какое-либо решение, как с этим справиться.

1 Ответ

1 голос
/ 27 мая 2020

Это действительно довольно просто, если вы «поговорите» с собой.

Простые части:

  • Просмотр стека ограничен
    • 8-pts Начальный и конечный
    • 16-pts снизу
    • >= 8-pts сверху
  • каждая кнопка имеет ограничения по высоте
    • >= 44
    • <= 56
  • высота верхнего вида "Dynami c" определяется его содержимым

«Хитрые» части:

  • добавить еще одно ограничение Top в представление стека
    • = 8-pts с .priority = .defaultHigh
    • , которое сообщает автоматическому макету «тянуть верхняя часть стека просматривается вверх ", если она не" опущена "(на максимальную высоту кнопок).
  • ограничивает высоту кнопок 2, 3 и 4 равной высота кнопки 1

Вот полный пример (весь код, без подключений к раскадровке). «Верхний» вид будет начинаться с высоты 240 пунктов ... каждый раз, когда вы нажимаете первую кнопку, высота вида сверху будет увеличиваться на 20, максимум до 400. На виде сверху также будут отображаться новые высоты:

class TestViewController: UIViewController {

    let stackView: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.spacing = 8
        return v
    }()

    let dynaView: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .yellow
        v.textAlignment = .center
        v.numberOfLines = 0
        return v
    }()

    var dynaViewHeightConstraint: NSLayoutConstraint!

    var theButtons: [UIButton] = [UIButton]()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(stackView)

        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([

            // stackView constrained 8-pts Leading and Trailing
            // 16-pts from bottom
            // >= 8-pts from top
            stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -16.0),
            stackView.topAnchor.constraint(greaterThanOrEqualTo: g.topAnchor, constant: 8.0),

        ])

        // we need a stackView TOP anchor = 8 with priorty 750
        //  this will "pull" the top up as far as it can, without violating the
        //  button height constraints
        let stackTop = stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0)
        stackTop.priority = .defaultHigh
        stackTop.isActive = true

        for i in 1...4 {
            let b = UIButton()
            b.translatesAutoresizingMaskIntoConstraints = false
            b.setTitle("Button \(i)", for: [])
            b.backgroundColor = .red
            NSLayoutConstraint.activate([
                // button heights are min: 44 max: 56
                b.heightAnchor.constraint(lessThanOrEqualToConstant: 56.0),
                b.heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0),
            ])
            theButtons.append(b)
        }

        // let's start with the dynaView height at 240
        dynaViewHeightConstraint = dynaView.heightAnchor.constraint(equalToConstant: 240.0)
        dynaViewHeightConstraint.isActive = true

        // add dynsView to the stack
        stackView.addArrangedSubview(dynaView)

        guard let firstButton = theButtons.first else {
            fatalError("Something is wrong with my setup!")
        }

        // add each button to the stack,
        //  setting its height equal to the first button's height
        theButtons.forEach { b in
            stackView.addArrangedSubview(b)
            if b != theButtons.first {
                b.heightAnchor.constraint(equalTo: firstButton.heightAnchor).isActive = true
            }
        }

        // tapping the first button will increae dynaView's height
        firstButton.addTarget(self, action: #selector(self.didTap(_:)), for: .touchUpInside)

    }

    override func viewDidAppear(_ animated: Bool) {
        showStats()
    }

    func showStats() -> Void {
        var s = "DynaView Height: \(dynaView.frame.height)"
        for i in 0..<theButtons.count {
            let b = theButtons[i]
            s += "\n"
            s += "Button \(i + 1) Height: \(b.frame.height)"
        }
        dynaView.text = s
    }

    @objc
    func didTap(_ sender: Any) -> Void {
        let h = min(dynaViewHeightConstraint.constant + 20, 400)
        dynaViewHeightConstraint.constant = h
        DispatchQueue.main.async {
            self.showStats()
        }
    }

}

Вот как это выглядит на iPhone 8 ...

enter image description here

enter image description here

и на iPhone 11 с высотой вида сверху при макс. 400:

enter image description here

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