Атрибут StackView isHidden не обновляется должным образом

Я пытаюсь обновить UIStackView, чтобы отображалось поле, если значение UITextField равно "Other". Вот мой код:

@IBOutlet var stackView: UIStackView!
func updateView() {
    print("UPDATING")
    UIView.animate(withDuration: 0.25, animations: { () -> Void in
         if(self.myTextField.text! == "Other") {
              print("SHOWING")
              self.stackView.arrangedSubviews[3].isHidden = false
         } else {
              print("HIDING")
              self.stackView.arrangedSubviews[3].isHidden = true
         }
         print("Is hidden: \(self.stackView.arrangedSubviews[3].isHidden )")
    })

Пример вывода выглядит так:

> UPDATING
> HIDING
> Is hidden: true
> UPDATING
> SHOWING
> Is hidden: true

Как вы можете видеть, атрибут isHidden отображается как true, независимо от того, что это было установлено в приведенном выше коде. Я не могу понять, почему это может быть, но, может быть, кто-то здесь может? Есть что-то очевидное, что нужно проверить? Есть ли причина, по которой isHidden не может быть обновлен? (обратите внимание, что на выходе нет ошибок).


person Ben    schedule 07.05.2017    source источник
comment
Если я возьму ваш образец кода плюс ваше описание буквально, он не будет работать из-за чувствительности к регистру - «другое» (как в вашем описании) по сравнению с «другим» (как в примере. Возможно, вы захотите принять во внимание следующее: self.myTextField.text!.lowercaseString == "other".   -  person Tom E    schedule 07.05.2017
comment
Извините, это просто плохое описание, я обновлю - см. Вывод для подтверждения   -  person Ben    schedule 07.05.2017
comment
@ Бен, ты понял? Решение zisoft удаляет анимацию, поэтому мне это не подходит. Если я удалю блок анимации, все будет работать должным образом.   -  person Levi    schedule 13.11.2017
comment
@Levi Я считаю, что ответ zisoft разрешил анимацию (похоже, он смотрит на код), однако на данный момент у меня нет рабочей копии, чтобы доказать это - извините!   -  person Ben    schedule 14.11.2017
comment
Нет проблем, я использовал обходной путь, при котором я устанавливаю элементы на отображение / скрытие также в блоке завершения анимации, а не только в блоке анимации. Мне не нравится решение, но оно исправило ошибку.   -  person Levi    schedule 14.11.2017


Ответы (3)


Обновления пользовательского интерфейса всегда должны выполняться в основном потоке (ЗАКОН).

Итак, оберните обновления пользовательского интерфейса в основной теме:

@IBOutlet var stackView: UIStackView!
func updateView() {
    print("UPDATING")
    UIView.animate(withDuration: 0.25, animations: { () -> Void in
        DispatchQueue.main.async {  // UI updates on the main thread
            if(self.myTextField.text! == "Other") {
                print("SHOWING")
                self.stackView.arrangedSubviews[3].isHidden = false
             } else {
                print("HIDING")
                self.stackView.arrangedSubviews[3].isHidden = true
             }
             print("Is hidden: \(self.stackView.arrangedSubviews[3].isHidden )")
        }
    })
person zisoft    schedule 07.05.2017
comment
Сработало отлично, спасибо! Вы знаете, почему UIView.animate по умолчанию не выполняется в основном потоке? Как еще можно было бы его использовать? - person Ben; 07.05.2017
comment
Рад помочь вам. Отметьте ответ как принятый. Анимации выполняются в другом потоке, чтобы предотвратить блокировку основного потока. - person zisoft; 07.05.2017
comment
Я не могу, пока не истечет таймер, но я, конечно, сделаю это. Я думаю, что это имеет смысл - так что вы не можете изменить свойство isHidden ни для чего, кроме основного потока, но как только они будут изменены, анимация может уйти от него. Спасибо еще раз! - person Ben; 07.05.2017
comment
Не думаю, что это правильное решение, в асинхронном режиме игнорируется продолжительность анимации. Если вы замените 0,25 секунды на 3 секунды, вы увидите, что это не работает. - person Ben; 14.07.2017

Это известная UIStackView ошибка (http://www.openradar.me/25087688). Об этом есть тема SO: (Swift: исчезающие представления из stackView). Короче:

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

Чтобы решить эту проблему, вы можете использовать следующее расширение:

extension UIView {
    var isHiddenInStackView: Bool {
        get {
            return isHidden
        }
        set {
            if isHidden != newValue {
                isHidden = newValue
            }
        }
    }
}
person Timur Bernikovich    schedule 14.03.2019
comment
Это была моя проблема с двойным скрытием элемента. Большое спасибо! - person finalpets; 29.08.2019
comment
Я все еще вижу эту проблему в iOS 13. У меня есть две метки в StackView в UITableViewCell, и одна или обе метки должны быть скрыты. Иногда метки были видны, даже если они были отмечены как скрытые. Мне удалось исправить это, только установив метки на Hidden true в раскадровке, а затем используя isHiddednInStackView для обновления их видимости. Если они начинали с isHidden false, а затем для isHidden было установлено значение true, они все равно иногда были видны. При повороте iPad ярлыки в некоторых рядах могут стать видимыми. - person PhoneyDeveloper; 26.03.2020

попробуйте управлять альфой вместе со свойством isHidden:

self.stackView.arrangedSubviews[3].isHidden = true
self.stackView.arrangedSubviews[3].alpha = 0

self.stackView.arrangedSubviews[3].isHidden = false
self.stackView.arrangedSubviews[3].alpha = 1
person Anton Novoselov    schedule 07.05.2017