Автоматическая разметка не работает, если отображается 1 метка, но работает с 2 метками - PullRequest
0 голосов
/ 05 июля 2019

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

Мой реальный вариант использования более сложный, но я попытался упростить его до кода ниже.

Код детской площадки Xcode 10.2 (Swift 5):

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
print(leadingConstraint.priority)
leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

let trailingConstraint = topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)
trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
topConstraint.priority = .defaultLow
topConstraint.isActive = true

let bottomConstraint = topologyView.bottomAnchor.constraint(greaterThanOrEqualTo: containerView.bottomAnchor)
bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
label1.setContentHuggingPriority(.required, for: .horizontal)
label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

print(topologyView.contentHuggingPriority(for: .horizontal))
print(topologyView.contentCompressionResistancePriority(for: .horizontal))

print(containerView.contentHuggingPriority(for: .horizontal))
print(containerView.contentCompressionResistancePriority(for: .horizontal))


Результат показан на рисунке ниже: a busy cat

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

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
print(leadingConstraint.priority)
leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

let trailingConstraint = topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)
trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
topConstraint.priority = .defaultLow
topConstraint.isActive = true

let bottomConstraint = topologyView.bottomAnchor.constraint(greaterThanOrEqualTo: containerView.bottomAnchor)
bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
label1.setContentHuggingPriority(.required, for: .horizontal)
label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let label2 = UILabel()
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "123124128"
label2.setContentHuggingPriority(.required, for: .horizontal)
label2.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label2)

label2.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label2.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label2.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label2.topAnchor.constraint(equalTo: label1.bottomAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

print(topologyView.contentHuggingPriority(for: .horizontal))
print(topologyView.contentCompressionResistancePriority(for: .horizontal))

print(containerView.contentHuggingPriority(for: .horizontal))
print(containerView.contentCompressionResistancePriority(for: .horizontal))

Результат показан на рисунке ниже: a busy cat

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

Интересно, почему в первом случае не работают должным образом ведущие и конечные ограничения (с 1 меткой), но работают во втором случае (с 2 метками))

Ответы [ 2 ]

1 голос
/ 08 июля 2019

У вас пара вещей идет не так, как надо.

Использование страницы игровой площадки с двумя метками "как есть", если вы измените текст label2 на:

label2.text = "01234567890 ABCDEFGHIJ"

Вы получите это:

enter image description here

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

Что происходит, когда: автоматическое расположение обрабатывает ограничения и обнаруживает, что оно не может полностью удовлетворить все из них, оно использует приоритеты, чтобы определить, какие из них можно нарушить, не выдавая ошибку. В вашем случае вы устанавливаете различные ограничения и приоритеты, которые неверны , предоставляя автоматическому макету разрешение на изменение макета.

Итак, во-первых, я не знаю, откуда у вас возникла идея установить приоритет для topologyView ограничений на ведение, трейлинг, верх и низ на .defaultLow. в явном виде предписывает автоматическому макету игнорировать эти ограничения, если это необходимо. Затем вы добавляете метку, которая будет шире topologyView, и автоматическая разметка будет следовать вашим инструкциям и нарушит ограничения.

В вашем примере с «двумя метками» автоматическое расположение отдает приоритет label2 - что просто произошло , чтобы сделать его правильным (пока вы не сделаете метку шире).

Далее, вы используете greaterThanOrEqualTo неправильно. Установив:

topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)

вы говорите: "позвольте заднему фронту topologyView перейти за заднему фронту containerView. Что вы действительно хотите, это меньше :

topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)

Это сохранит задний край topologyView меньше задний край containerView.

Теперь неясно, хотите ли вы, чтобы метки помещались на всю ширину containerView, или если вы хотите, чтобы они центрировались, если они оба короткие.

Если полная ширина, используйте equalTo ... если отцентрировано, используйте greatThanOrEqualTo в начале и lessThanOrEqualTo в конце.

То же самое относится и к нижнему ограничению.

Итак ... ваш пример "одного ярлыка" становится:

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
// use default priority
//leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

// use lessThanOrEqualTo
let trailingConstraint = topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
// use default priority
//trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
// use default priority
//topConstraint.priority = .defaultLow
topConstraint.isActive = true

// use lessThanOrEqualTo
let bottomConstraint = topologyView.bottomAnchor.constraint(lessThanOrEqualTo: containerView.bottomAnchor)
// use default priority
//bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.backgroundColor = .yellow
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
// we can leave Hugging and Compression at default Priority
//label1.setContentHuggingPriority(.required, for: .horizontal)
//label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

В результате (короткая метка):

enter image description here

или (длинная метка):

enter image description here

И ваш пример с двумя метками:

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
// use default priority
//leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

// use lessThanOrEqualTo
let trailingConstraint = topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
// use default priority
//trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
// use default priority
//topConstraint.priority = .defaultLow
topConstraint.isActive = true

// use lessThanOrEqualTo
let bottomConstraint = topologyView.bottomAnchor.constraint(lessThanOrEqualTo: containerView.bottomAnchor)
// use default priority
//bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.backgroundColor = .yellow
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
// we can leave Hugging and Compression at default Priority
//label1.setContentHuggingPriority(.required, for: .horizontal)
//label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let label2 = UILabel()
label2.backgroundColor = .orange
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "012345 ABCDE"
// we can leave Hugging and Compression at default Priority
//label2.setContentHuggingPriority(.required, for: .horizontal)
//label2.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label2)

label2.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label2.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label2.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label2.topAnchor.constraint(equalTo: label1.bottomAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

с короткой и длинной этикеткой:

enter image description here

enter image description here

0 голосов
/ 05 июля 2019

Я нашел, что вы устанавливаете label1.setContentHuggingPriority(.required, for: .horizontal). Пожалуйста, попробуйте уменьшить приоритет до high вместо require.

...