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

#ios #swift #uiview #autolayout

#iOS #swift #uiview #автоматическое описание

Вопрос:

У меня есть два UILabel (вертикальное направление) в UIView и UIButton в одной «строке». Мне нужно получить этот результат: введите описание изображения здесь

Просматривает код инициализации:

 private lazy var contentView: UIView = {
    let view = UIView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false

    return view
  }()

  private lazy var priceView: UIView = {
    let view = UIView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.setContentHuggingPriority(.required, for: .horizontal)

    return view
  }()

  private lazy var priceLabel: UILabel = {
    let label = UILabel(frame: .zero)
    label.numberOfLines = 1
    label.translatesAutoresizingMaskIntoConstraints = false

    return label
  }()

  private lazy var oldPriceLabel: UILabel = {
    let label = UILabel(frame: .zero)
    label.numberOfLines = 1
    label.translatesAutoresizingMaskIntoConstraints = false

    return label
  }()

  private lazy var callButton: UIButton = {
    let button = UIButton(frame: .zero)
    button.translatesAutoresizingMaskIntoConstraints = false
    button.layer.cornerRadius = 22.0
    button.setTitleColor(.white, for: .normal)
    button.setTitle("Call", for: .normal)
    button.setContentHuggingPriority(.defaultLow, for: .horizontal)
    button.setContentCompressionResistancePriority(.required, for: .horizontal)

    return button
  }()
 

Используя SnapKit, я создаю ограничения:

 self.contentView.snp.makeConstraints { make in
  make.top.bottom.equalToSuperview()
  make.left.equalToSuperview().offset(16.0)
  make.right.equalToSuperview().offset(-16.0)
}
  self.priceView.snp.makeConstraints { make in
    make.centerY.left.equalToSuperview()
    make.right.equalTo(self.callButton.snp.left)

  }
  self.priceLabel.snp.makeConstraints { make in
    make.left.equalToSuperview()
    make.top.equalToSuperview()
    make.right.lessThanOrEqualToSuperview()
  }

  self.oldPriceLabel.snp.makeConstraints { make in
    make.left.bottom.equalToSuperview()
    make.top.equalTo(self.priceLabel.snp.bottom).offset(8.0)
    make.right.lessThanOrEqualToSuperview()
  })
  self.callButton.snp.makeConstraints { make in
   make.left.equalTo(self.priceView.snp.right)
    make.centerY.equalToSuperview()
    make.height.equalTo(44.0)
    make.right.equalToSuperview()

  }
 

Я хочу priceView уменьшить размер UILabels и callButton растянуть на все свободное пространство. Сжатие и сжатие не работают, и я не понимаю, почему.

Теперь: введите описание изображения здесь

Комментарии:

1. Ограничения зависят от того, как вы хотели видеть одинаковый пользовательский интерфейс на устройствах разного размера. Пожалуйста, обновите вопрос.

2. размер не имеет значения. Высота фиксирована. Если ширина изменится, кнопка получит все свободное пространство.

3. Смотрите мой ответ, @AleksandrMaybach

4. Вы хотите, чтобы ваши метки или ваша кнопка имели фиксированную ширину? Например, если ваши «цены» равны 500 and 600 , кнопка будет намного шире, чем если бы ваши цены были 500 000 000 равны and 999 999 999 999 .

Ответ №1:

Если вы не хотите использовать a UIStackView , вы можете легко исправить свою проблему…

Для каждой метки измените:

 make.right.lessThanOrEqualToSuperview()
 

Для:

 make.right.equalToSuperview()
 

и это должно исправить.

Комментарии:

1. Да, я использовал это. Это работает, но почему??? если у меня есть два условия right = right, почему система автозапуска используется больше всего.

2. По умолчанию приоритет горизонтального охвата содержимого для a UILabel низкий (250), а сопротивление сжатию содержимого высокое (750). Таким образом, каждая метка будет расширяться, чтобы соответствовать своему тексту, И расширяться, чтобы придерживаться правого края своего супервизора (с этими ограничениями).

Ответ №2:

Во-первых, вам не нужно устанавливать translateAutoresizingMaskIntoConstraints значение false в каждом из ваших представлений, поскольку вы устанавливаете их ограничения с помощью SnapKit.

Далее, лучший способ справиться с тем, что вы хотите, — это использовать назначение UIStackView .

Это просто, как это:

 self.view.addSubview(self.stackView_Main)
self.stackView_Main.snp.makeConstraints { (make) in
    make.height.equalTo(44.0)
    make.leading.trailing.equalToSuperview().inset(16.0)
    make.top.equalToSuperview().inset(100.0)
}

self.callButton.snp.makeConstraints { (make) in
    make.top.bottom.equalToSuperview()
}
 

И вы получите это отлично, без предупреждений:

введите описание изображения здесь

Полный пример кода:

 import SnapKit
import UIKit

class ViewController: UIViewController {

    private lazy var stackView_Main: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [self.stackView_Price, self.callButton])
        stackView.axis = .horizontal
        stackView.spacing = 5.0
        stackView.alignment = .leading
        stackView.distribution = .fill
        return stackView
    }()

    private lazy var stackView_Price: UIStackView = {
        let stackView = UIStackView(arrangedSubviews: [self.priceLabel, self.oldPriceLabel])
        stackView.axis = .vertical
        stackView.spacing = 5.0
        return stackView
    }()

    private lazy var priceLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.numberOfLines = 1
        label.text = "500 000 000"
        return label
    }()

    private lazy var oldPriceLabel: UILabel = {
        let label = UILabel(frame: .zero)
        label.numberOfLines = 1
        label.text = "999 999 999 999"
        return label
    }()

    private lazy var callButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.layer.cornerRadius = 22.0
        button.backgroundColor = .black
        button.setTitleColor(.white, for: .normal)
        button.setTitle("Call", for: .normal)
        button.setContentHuggingPriority(.defaultLow, for: .horizontal)
        button.setContentCompressionResistancePriority(.required, for: .horizontal)

        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()


        self.view.addSubview(self.stackView_Main)
        self.stackView_Main.snp.makeConstraints { (make) in
            make.height.equalTo(44.0)
            make.leading.trailing.equalToSuperview().inset(16.0)
            make.top.equalToSuperview().inset(100.0)
        }

        self.callButton.snp.makeConstraints { (make) in
            make.top.bottom.equalToSuperview()
        }
    }


}
 

Дайте мне знать, если это поможет 😉

Комментарии:

1. Я думал об UIStackView этом, и ваш ответ очень полезен, но возможно ли обойтись без этого UIStackView ?

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