Подтвердить что ты не робот

UIStackView - проблемы с ограничением компоновки при скрытии представлений стека

В моем приложении есть 2 экрана:

  • TableViewVC (здесь нет представлений стека)

  • DetailVC (все вложенные представления стека здесь, см. ссылку на картинку: Изображение вложенных стоп-кадров). Обратите внимание: есть ярлыки и изображения в этих представлениях стека.

Когда вы нажимаете ячейку в представлении таблицы, она передает информацию из TableViewVC в DetailVC. Проблема заключается в том, что скрывает определенные UIStackViews в DetailVC. Я хочу, чтобы только 2 представления стека из разных в DetailVC были скрыты, как только загрузится представление. Поэтому я пишу этот код в DetailVC, чтобы выполнить это:

override func viewDidLoad() {
    super.viewDidLoad()

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true
}

Все выглядит великолепно, но Xcode дает много предупреждений только в время исполнения. Когда приложение не работает, никаких предупреждений в раскадровке нет. См. Ссылку на изображение ошибок: Изображение ошибок

В основном это много UISV-скрытия, UISV-интервал, ошибки UISV-canvas-connection. Эти ошибки исчезают, если я скрываю те же представления стека в viewDidAppear, но затем появляется флеш материала, который должен был быть скрыт, а затем он скрывается. Пользователь видит краткий обзор, а затем скрывает, что не очень хорошо.

Извините за то, что вы не можете отправлять фотографии, а не ссылки, но не можете этого сделать.

Любые предложения по устранению этого? Это приложение, которое я действительно хочу запустить в магазин приложений - это мое первое, поэтому любая помощь будет замечательной!

Изменить/Обновить 1:

Я нашел небольшую работу с этим кодом, который я разместил во втором экране с именем DetailVC:

// Function I use to delay hiding of views
func delay(delay: Double, closure: ()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

// Hide the 2 stack views after 0.0001 seconds of screen loading
override func awakeFromNib() {
    delay(0.001) { () -> () in
        self.summaryStackView.hidden = true
        self.combinedStackView.hidden = true
    }
}

// Update view screen elements after 0.1 seconds in viewWillAppear
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    delay(0.1) { () -> () in
        self.nameLabel.text = "John"
    }
}

Это полностью избавляет от предупреждений о ограничениях макета из Xcode.

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

Любые предложения относительно того, почему это избавляет от предупреждений? Кроме того, любые предложения о том, как улучшить это, чтобы работать отлично??? Спасибо!

4b9b3361

Ответ 1

Вы пробовали это, назвав супер после ваших изменений?

override func viewWillAppear() {

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true

    super.viewWillAppear()
}

Ответ 2

У меня была та же проблема, и я исправил ее, указав ограничения высоты моих изначально скрытых просмотров на приоритет 999.

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

Проблема заключается в том, что ваш стековый режим применяет ограничение высоты 0 на вашем скрытом виде, которое конфликтует с вашим другим ограничением по высоте. Это сообщение об ошибке:

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:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>",
    "<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>"
)

Предоставляя ограничение по высоте, более низкий приоритет решает эту проблему.

Ответ 3

Это известная проблема с скрытием вложенных представлений стека.

Существуют 3 решения этой проблемы:

  • Измените интервал на 0, но тогда вам нужно будет запомнить предыдущее значение расстояния.
  • Вызовите innerStackView.removeFromSuperview(), но тогда вам нужно будет запомнить, куда вставить представление стека.
  • Оберните представление стека в UIView с хотя бы одним ограничением 999. Например. Top, Leading, Trailing @1000, Bottom @999.

Третий вариант - лучший, на мой взгляд. Для получения дополнительной информации об этой проблеме, о том, почему это происходит, о различных решениях и о том, как реализовать решение 3, см. мой ответ на аналогичный вопрос.

Ответ 4

Вы можете использовать свойство removeArrangedSubview и removeFromSuperview для UIStackView.

В Objective-C:

 [self.topStackView removeArrangedSubview:self.summaryStackView];
 [self.summaryStackView removeFromSuperview];

 [self.topStackView removeArrangedSubview:self.combinedStackView];
 [self.combinedStackView removeFromSuperview];

Из Apple UIStackView Документация:(https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//apple_ref/occ/instm/UIStackView/removeArrangedSubview:)

Просмотр стека автоматически обновляет его расположение всякий раз, когда представления добавляются, удаляются или вставляются в массив builtSubviews.

  • removeArrangedSubview: этот метод удаляет предоставленное представление из массива stackSubviews. Позиция и размер представлений больше не будут управляться представлением стека. Однако этот метод не удаляет предоставленное представление из массива subviews стеков; поэтому представление все еще отображается как часть иерархии представлений.

Чтобы запретить появление представления на экране после вызова стеков removeArrangedSubview: метод, явным образом удалить представление из массива subviews, вызвав метод removeFromSuperview, или установить для скрытого свойства views значение YES.

Ответ 5

Когда UIViewStack скрыт, ограничения, автоматически генерируемые UIStackView, будут вызывать множество UISV-скрывающих, UISV-интервалов, предупреждений UISV-canvas-connection, если свойство интервала UIStackView имеет любое значение, отличное от нуля.

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

if hideStackView {
    myStackView.hidden = true
    myStackView.spacing = CGFloat(0)
} else {
    myStackView.hidden = false
    myStackView.spacing = CGFloat(8)
}

Ответ 6

Я переместил весь код UIStackView.hidden из viewDidLoad в viewDidAppear и проблема с ограниченными ограничениями исчезла. В моем случае все конфликтующие ограничения были сгенерированы автоматически, поэтому не удалось настроить приоритеты.

Я также использовал этот код, чтобы сделать его более красивым:

UIView.animateWithDuration(0.5) {
    self.deliveryGroup.hidden = self.shipVia != "1"
}

EDIT:

Также необходим следующий код, чтобы остановить его при повторном запуске устройства:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    self.deliveryGroup.hidden = false

    coordinator.animateAlongsideTransition(nil) {
    context in
        self.deliveryGroup.hidden = self.shipVia != "1"
    }
}

Ответ 7

Я исправил это, поместив команды hide в traitCollectionDidChange.

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    self.item.hidden = true
}

Ответ 8

Я обнаружил, что вложенные UIStackViews показывают это поведение, если вы задали скрытое свойство в ✨Interface Builder✨. Мое решение состояло в том, чтобы все было не скрыто в "Внутреннем Builder" и выборочно скрывать вещи в viewWillAppear.

Ответ 9

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

UPD: у вас довольно сложная структура просмотров. Не видя ограничений, трудно сказать, что именно не так. Тем не менее, я бы предложил построить иерархию представлений, постепенно добавляя представления один за другим и следя за тем, чтобы не было предупреждений о времени разработки/времени выполнения. Прокрутка может добавить еще один уровень сложности, если вы не справитесь с этим правильно. Узнайте, как использовать ограничения со списком прокрутки. Все остальные временные хаки не являются решением в любом случае.

Ответ 10

Поместите свои команды hide в viewWillLayoutSubviews() {}