Когда мои «строки» UIStackView сжаты, они выдают AutoLayout
предупреждения. Тем не менее, они отображаются нормально, и ничего плохого, кроме этих видов журналов:
Невозможно одновременно удовлетворить ограничения. Возможно, по крайней мере одно из ограничений в следующем списке вам не нужно. Попробуйте следующее: (1) посмотрите на каждое ограничение и попытайтесь выяснить, чего вы не ожидаете; (2) найдите код, добавивший нежелательное ограничение или ограничения, и исправьте его. (Примечание: если вы видите,
NSAutoresizingMaskLayoutConstraints
что не понимаете, см. Документацию по этомуUIView
свойствуtranslatesAutoresizingMaskIntoConstraints
) (
Итак, я еще не уверен, как это исправить, но, похоже, это ничего не ломает, кроме того, что просто раздражает.
Кто-нибудь знает как это решить? Интересно, что ограничения макета довольно часто помечаются тегом «UISV-hiding» , что указывает на то, что, возможно, в этом случае следует игнорировать минимумы высоты для подпредставлений или чего-то еще?
источник
Ответы:
Вы получаете эту проблему, потому что при установке подпредставления изнутри
UIStackView
на скрытый, он сначала ограничивает его высоту до нуля, чтобы оживить его.Я получал следующую ошибку:
2015-10-01 11:45:13.732 <redacted>[64455:6368084] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180] (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5bdfbda0 'UISV-hiding' V:[UIView:0x7f7f5be69d30(0)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
То, что я пытался сделать, заключалось в том, чтобы разместить
UIView
внутриUIStackView
себяUISegmentedControl
вставку по 8 пунктов на каждом краю.Когда я установил его на скрытый, он попытался ограничить представление контейнера нулевой высотой, но поскольку у меня есть набор ограничений сверху вниз, возник конфликт.
Чтобы решить эту проблему, я изменил приоритет ограничений 8pt (верхний и нижний) с 1000 на 999, чтобы при необходимости
UISV-hiding
ограничение могло иметь приоритет.источник
У меня была аналогичная проблема, которую было нелегко решить. В моем случае у меня было представление стека, встроенное в представление стека. Для внутреннего UIStackView были заданы две метки и ненулевой интервал.
Когда вы вызываете addArrangedSubview (), он автоматически создает ограничения, подобные следующим:
V:|[innerStackView]| | = outerStackView V:|[label1]-(2)-[label2]| | = innerStackView
Теперь, когда вы пытаетесь скрыть innerStackView, вы получаете предупреждение о неоднозначных ограничениях.
Чтобы понять почему, давайте сначала посмотрим, почему этого не происходит, когда
innerStackView.spacing
равно0
. Когда вы звонитеinnerStackView.hidden = true
, @liamnichols был прав ...outerStackView
он волшебным образом перехватит этот звонок и создаст0
высоту скрывающее UISV, с приоритетом 1000 (обязательно). Предположительно, это сделано для того, чтобы элементы в представлении стека были анимированы вне поля зрения в случае, если ваш код скрытия вызывается внутриUIView.animationWithDuration()
блока. К сожалению, не существует способа предотвратить добавление этого ограничения. Тем не менее вы не получите предупреждение «Невозможно одновременно удовлетворить ограничениям» (USSC), поскольку произойдет следующее:Ясно, что эти 4 ограничения могут быть удовлетворены. Представление стека просто превращает все в пиксель нулевой высоты.
Теперь вернемся к примеру с ошибкой, если мы установим
spacing
значение2
, теперь у нас есть следующие ограничения:Вид стека не может одновременно иметь высоту 0 пикселей и высоту содержимого 2 пикселя. Ограничения не могут быть выполнены.
Примечание. Вы можете увидеть это поведение на более простом примере. Просто добавьте UIView в представление стека в виде упорядоченного подпредставления. Затем установите ограничение высоты для этого UIView с приоритетом 1000. А теперь попробуйте позвонить по этому поводу.
Примечание. По какой-то причине это произошло только тогда, когда мое представление стека было подвидом UICollectionViewCell или UITableViewCell. Однако вы все равно можете воспроизвести это поведение за пределами ячейки, вызвав
innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
следующий цикл выполнения после скрытия внутреннего представления стека.Примечание. Даже если вы попытаетесь выполнить код в UIView.performWithoutAnimations, в представлении стека все равно будет добавлено ограничение высоты 0, что вызовет предупреждение USSC.
Есть как минимум 3 решения этой проблемы:
spacing
на 0. Это раздражает, потому что вам нужно полностью изменить процесс (и запомнить исходный интервал) всякий раз, когда вы снова показываете содержимое.removeFromSuperview
. Это еще более раздражает, так как, когда вы обращаете процесс вспять, вам нужно помнить, куда вставить удаленный элемент. Вы можете оптимизировать, только вызвав removeArrangedSubview, а затем скрывшись, но еще предстоит выполнить много бухгалтерии.spacing
) в UIView. Укажите хотя бы одно ограничение как необязательный приоритет (999 или ниже). Это лучшее решение, поскольку вам не нужно вести бухгалтерский учет. В моем примере я создал верхние, ведущие и конечные ограничения на уровне 1000 между представлением стека и представлением оболочки, а затем создал ограничение 999 от нижней части представления стека до представления оболочки. Таким образом, когда внешний вид стека создает ограничение нулевой высоты, ограничение 999 нарушается, и вы не видите предупреждения USSC. (Примечание: это похоже на решение, если для contentView.translatesAutoResizingMaskToConstraints подкласса UICollectionViewCell должно быть установлено значениеfalse
)Таким образом, причины такого поведения:
Если бы Apple либо (1) позволила вам указать приоритет ограничений (особенно разделителей), либо (2) разрешила вам отказаться от автоматического ограничения UISV-сокрытия , эта проблема была бы легко решена.
источник
UIStackView
дочернего элементаUIStackView
в aUIView
или только того, который вы хотите скрыть / показать?UIStackView
обычно загадочны и трудны для понимания.В большинстве случаев эту ошибку можно устранить, снизив приоритет ограничений для устранения конфликтов.
источник
Когда вы устанавливаете вид как скрытый, он
UIStackview
будет пытаться отменить его анимацию. Если вам нужен этот эффект, вам нужно установить правильный приоритет для ограничений, чтобы они не конфликтовали (как многие предлагали выше).Однако, если вам не нужна анимация (возможно, вы скрываете ее в ViewDidLoad), вы можете просто,
removeFromSuperview
что будет иметь тот же эффект, но без каких-либо проблем с ограничениями, поскольку они будут удалены вместе с представлением.источник
Основываясь на ответе @Senseful, вот расширение UIStackView для обертывания представления стека в представление и применения ограничений, которые он или она рекомендует:
/// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`). /// See http://stackoverflow.com/questions/32428210 func wrapped() -> UIView { let wrapper = UIView() translatesAutoresizingMaskIntoConstraints = false wrapper.addSubview(self) for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] { let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: wrapper, attribute: attribute, multiplier: 1, constant: 0) if attribute == .Bottom { constraint.priority = 999 } wrapper.addConstraint(constraint) } return wrapper }
Вместо добавления своего
stackView
используйтеstackView.wrapped()
.источник
Во-первых, как предлагали другие, убедитесь, что ограничения, которыми вы можете управлять, то есть не ограничения, присущие UIStackView, имеют приоритет 999, чтобы их можно было переопределить, когда представление скрыто.
Если проблема все еще не устранена, проблема, скорее всего, связана с интервалом в скрытых StackViews. Мое решение заключалось в том, чтобы добавить UIView в качестве разделителя и установить интервал UIStackView равным нулю. Затем установите ограничения View.height или View.width (в зависимости от вертикального или горизонтального стека) на интервал StackView.
Затем настройте приоритеты объятий контента и сопротивления сжатию контента ваших недавно добавленных представлений. Возможно, вам также придется изменить распределение родительского StackView.
Все вышеперечисленное можно сделать в Интерфейсном Разработчике. Вам также может потребоваться программно скрыть / отобразить некоторые из недавно добавленных представлений, чтобы у вас не было нежелательных интервалов.
источник
Недавно я столкнулся с ошибками автоматической компоновки при скрытии файла
UIStackView
. Вместо того, чтобы вести кучу бухгалтерии и упаковывать стопкиUIViews
, я решил создать выход для своихparentStackView
и выходы для детей, которых я хочу скрыть / показать.@IBOutlet weak var parentStackView: UIStackView! @IBOutlet var stackViewNumber1: UIStackView! @IBOutlet var stackViewNumber2: UIStackView!
Вот как выглядит мой parentStack в раскадровке:
У него 4 дочерних элемента, и каждый из них имеет внутри несколько видов стека. Когда вы скрываете представление стека, если у него есть элементы пользовательского интерфейса, которые также являются представлениями стека, вы увидите поток ошибок автоматического макета. Вместо того, чтобы прятаться, я решил удалить их.
В моем примере он
parentStackViews
содержит массив из 4 элементов: Top Stack View, StackViewNumber1, Stack View Number 2 и Stop Button. Их индексы вarrangedSubviews
равны 0, 1, 2 и 3 соответственно. Когда я хочу скрыть один, я просто удаляю его изparentStackView's
arrangedSubviews
массива. Поскольку он неслабый, он остается в памяти, и вы можете просто вернуть его в желаемый индекс позже. Я не инициализирую его повторно, поэтому он просто зависает, пока не понадобится, но не раздувает память.В общем, вы можете ...
1) Перетащите IBOutlets для родительского стека и дочерних элементов, которых вы хотите скрыть / отобразить, на раскадровку.
2) Если вы хотите их скрыть, удалите стек, который вы хотите скрыть из
parentStackView's
arrangedSubviews
массива.3) Звоните
self.view.layoutIfNeeded()
сUIView.animateWithDuration
.Обратите внимание, что последние два stackView - нет
weak
. Вам нужно держать их под рукой, пока вы их не покажете.Скажем, я хочу скрыть stackViewNumber2:
parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview()
Затем оживите его:
UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Если вы хотите «показать»
stackViewNumber2
позже, вы можете просто вставить его в нужныйparentStackView
arrangedSubViews
индекс и анимировать обновление.parentStackView.removeArrangedSubview(stackViewNumber1) stackViewNumber1.removeFromSuperview() parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) // Then animate it UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Я обнаружил, что это намного проще, чем вести учет ограничений, возиться с приоритетами и т. Д.
Если у вас есть что-то, что вы хотите скрыть по умолчанию, вы можете просто выложить это на раскадровку, удалить
viewDidLoad
и обновить без использования анимацииview.layoutIfNeeded()
.источник
У меня были те же ошибки со встроенными представлениями стека, хотя во время выполнения все работало нормально.
Я решил ошибки ограничения, сначала скрыв все представления подстека (настройка
isHidden = true
), прежде чем скрыть представление родительского стека.Это не имело всей сложности, связанной с удалением подгруппированных представлений и поддержанием индекса, когда необходимо добавить их обратно.
Надеюсь это поможет.
источник
Senseful предоставили отличный ответ на корень проблемы, описанной выше, поэтому я сразу перейду к решению.
Все, что вам нужно сделать, это установить приоритет всех ограничений stackView ниже 1000 (999 выполнит работу). Например, если stackView ограничен своим супервизором слева, справа, сверху и снизу, тогда все 4 ограничения должны иметь приоритет ниже 1000.
источник
Возможно, вы создали ограничение при работе с определенным классом размера (например, wCompact hRegular), а затем создали дубликат при переключении на другой класс размера (например, wAny hAny). проверьте ограничения объектов пользовательского интерфейса в разных классах размера и посмотрите, есть ли аномалии с ограничениями. вы должны увидеть красные линии, указывающие на столкновение ограничений. Я не могу разместить картинку, пока не наберу 10 очков репутации, извините: /
источник
Я хотел скрыть все UIStackView за раз, но я получал те же ошибки, что и OP, это исправило это для меня:
for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } }
источник
priority = 1000
) на not required (priority <= 999
).У меня был ряд кнопок с ограничением по высоте. Это происходит, когда одна кнопка скрыта. Установка приоритета ограничения высоты кнопок на 999 устранила проблему.
источник
Эта ошибка не имеет ничего общего с UIStackView. Это происходит, когда у вас есть конфликтные ограничения с одинаковыми приоритетами. Например, если у вас есть ограничение, указывающее, что ширина вашего представления равна 100, и у вас есть другое ограничение, в то же время указывается, что ширина представления составляет 25% от его контейнера. Очевидно, есть два противоречащих друг другу ограничения. Решение - удалить одно из них.
источник
NOP с [mySubView removeFromSuperview]. Надеюсь, это может кому-то помочь :)
источник