Обновление UILabels Вне Экрана, Вызывающее Их "Привязку" Назад


Справочная Информация

Я создаю крошечный секундомер. Он состоит из основного вида с меткой, отображающей время, и двух кнопок: start & stop.
Кнопка start активирует NSTimers, которая затем вызывает методы, вычисляющие прошедшее время, а затем обновляет метки соответствующим образом. Кнопка стоп просто делает таймеры недействительными.

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

Выпуск

Однако при одновременном запуске таймеров и, таким образом, обновлении меток вскоре после начала анимации все возвращается в прежнее положение. При отключении таймеров с помощью кнопки stop анимация снова работает нормально.

Демо

Демонстрация выпуска

Код

Анимация в toggleMenu()

UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .CurveEaseOut, animations: {
    if self.arrow.frame.origin.x >= screenBounds.width/2 {
        //if menu is NOT visible (mainView ON-SCREEN, menu right)
        for element in self.UIElements {element.frame.origin.x -= screenBounds.width}
        self.arrow.frame.origin.x = 0
        self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))
    } else {
        //if menu IS visible (mainView left, menu ON-SCREEN)
        for element in self.UIElements {element.frame.origin.x += screenBounds.width}
        self.arrow.frame.origin.x = screenBounds.width-self.arrow.frame.width
        self.arrow.transform = CGAffineTransformMakeRotation(CGFloat(0))
    }
    }, completion: nil)

Обновление меток в таймере называется updateTime()

let currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime: NSTimeInterval = currentTime - startTime

let hrs = UInt8(elapsedTime/3600)
elapsedTime -= NSTimeInterval(hrs)*3600
let mins = UInt8(elapsedTime/60)
elapsedTime -= NSTimeInterval(mins)*60
let secs = UInt8(elapsedTime)
elapsedTime -= NSTimeInterval(secs)

let strHrs  = String(format: "%02d", hrs)
let strMins = String(format: "%02d", mins)
let strSecs = String(format: "%02d", secs)

//update time labels
self.time.text = "(strHrs):(strMins)"
self.secs.text = "(strSecs)"

Попытки

Безуспешно я пытался...

  • ...прячется на этикетках как только анимация заканчивается
  • ...анимация / скрытие супервизора всех элементов после завершения анимации (clipsToBounds Установить true)

Примечание

Я прикинул...

  • ...комментируя строки, где метки обновляются "исправляет" проблему
  • ...анимация Элементы пользовательского интерфейса для перемещения только пару пикселей (например, 100px) вызывает ту же проблему, а это означает, что проблема происходит на экране и за его пределами


Есть какие-нибудь мысли?
Заранее спасибо!

1 2

1 ответ:

При обновлении меток запускается Auto Layout , который возвращает элементы пользовательского интерфейса туда, где они должны быть ограничены. Вы не должны изменять фреймы объектов, находящихся под управлением Auto Layout , иначе вы получите неожиданные результаты.

Вместо обновления origin.x элементов пользовательского интерфейса создайте @IBOutlets для NSLayoutContraints, расположив их горизонтально, а затем обновите свойство constant ограничений и вызовите self.view.layoutIfNeeded() в анимации петля.

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