Свифт программно добавленные ограничения не работают - PullRequest
0 голосов
/ 26 января 2020

У меня есть представление внутри прокрутки:

enter image description here

Теперь я хочу программно добавить дочерние виды в это представление. Вот мой код, чтобы сделать это:

  1. дочерний вид (работает)

    //Adds header to the view again because it was removed in the clear() method
    //Header is just a label
    lv.addSubview(header)
    header.leadingAnchor.constraint(equalTo: header.superview!.leadingAnchor).isActive = true
    header.topAnchor.constraint(equalTo: header.superview!.topAnchor, constant: 2).isActive = true
    header.widthAnchor.constraint(equalTo: header.superview!.widthAnchor).isActive = true
    header.heightAnchor.constraint(equalToConstant: MainTabViewController.fontSize*3).isActive = true //Just a constant
    

Теперь я выполняю этот код несколько раз:

private func makeTextLabel(text: NSAttributedString, bgColor: UIColor?, maxWidth: CGFloat?) -> UILabel {
    //Creates label
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    lv.addSubview(label)
    //Adjustments
    if(bgColor != nil) {
        label.backgroundColor = bgColor
    }
    label.textColor = UIColor.black
    label.attributedText = text
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    let width = maxWidth ?? lv.frame.size.width-8
    label.widthAnchor.constraint(equalToConstant: width).isActive = true
    label.heightAnchor.constraint(equalToConstant: heightForLabel(attributedText: label.attributedText, width: width)).isActive = true
    label.leadingAnchor.constraint(equalTo: lv.leadingAnchor, constant: 4).isActive = true
    let previousView = lv.subviews[lv.subviews.count-1]
    label.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant:  10).isActive = true
    return label
}

Все метки добавлены, но ограничения не работают вообще. Вот как это выглядит (когда я выполняю метод выше 2 раза):

enter image description here

РЕДАКТИРОВАТЬ: Основная проблема решена. Сейчас я использую StackView. ({ ссылка })

Теперь я хочу, чтобы мои метки имели смещение по краям, поэтому я использую эти строки:

    label.leadingAnchor.constraint(equalTo: lessonStackView.leadingAnchor, constant: offset).isActive = true
    label.trailingAnchor.constraint(equalTo: lessonStackView.trailingAnchor, constant: -offset).isActive = true

Но так как StackView, кажется, сам устанавливает x-ограничения, я получаю это предупреждение:

Невозможно одновременно удовлетворить ограничения. Возможно, по крайней мере одно из ограничений в следующем списке - это то, что вам не нужно. Попробуйте это: (1) посмотреть на каждое ограничение и попытаться выяснить, чего вы не ожидаете; (2) найдите код, который добавил нежелательное ограничение или ограничения, и исправьте его. ("UILabel: 0x7f9c16c22c30'Falls dir d ie App gef \ U00e4llt ... '(active, names:' | ': JavaProf.MultipleContentsView: 0x7f9c19024a60)>", "", "") *

Будет ли попытаться восстановить, нарушив ограничение

Как я могу решить это?

Ответы [ 2 ]

1 голос
/ 27 января 2020

Если вы хотите использовать UIStackView для стека меток (или других видов), и вы хотите, чтобы они имели различный начальный интервал, у вас есть пара вариантов:

1) Вставить метку в UIView. Пусть UIView заполняет ширину представления стека и присваивает представлению ограничения на метки.

2) Установите представление стека Aligment в Trailing. Затем добавьте ограничение ширины для каждой метки, равное ширине представления стека. Для метки, которую вы хотите иметь, скажем, 32-точечное «левое поле», установите для константы на этой метке значение -32.

Вот краткий пример:

class LeftMarginViewController: UIViewController {
    let stackView: UIStackView = {
        let v = UIStackView()
        v.axis = .vertical
        v.alignment = .trailing
        v.distribution = .fill
        v.spacing = 8
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        for i in 1...7 {
            let v = UILabel()
            v.backgroundColor = .yellow
            v.numberOfLines = 0
            if i == 5 {
                v.text = "Label 5 has a lot of text to demonstrate what happens when it needs to wrap onto multiple lines."
            } else {
                v.text = "Label \(i)"
            }
            stackView.addArrangedSubview(v)
            switch i {
            case 6:
                v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -32.0).isActive = true
            case 2, 4, 5:
                v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: -16.0).isActive = true
            default:
                v.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1.0, constant: 0.0).isActive = true
            }
        }

        stackView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stackView)

        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
            stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
        ])

    }
}

Вид стека имеет Alignment: Trailing, каждая метка имеет ширину, равную ширине вида стека, метки 2, 4 и 5 имеют constant = -16, а метка 6 имеет constant = -32.

Результат:

enter image description here

0 голосов
/ 26 января 2020

Удалить width якорь. Вам не нужно заботиться о ширине (и вы действительно ее не знаете), вместо этого используйте trailingAnchor:

label.trailingAnchor.constraint(equalTo: lv.trailingAnchor, constant: -4).isActive = true

Remove heightAnchor, вместо этого позвольте системе рассчитать высоту для вас:

label.setContentHuggingPriority(.required, for: .vertical)
label.setContentCompressionResistancePriority(.required, for: .vertical)

Это должно быть все необходимое.

Однако, в качестве примечания, вместо создания ограничения для предыдущей метки, вы можете просто использовать UIStackView.

...