2014-03-22 2 views
7

Я хочу наблюдать изменения в координате x моего источника UIView, когда он анимируется с использованием animateWithDuration:delay:options:animations:completion:. Я хочу отслеживать изменения в координате x во время этой анимации на гранулированном уровне, потому что я хочу изменить взаимодействие с другим представлением, с которым может взаимодействовать анимированный вид. Я хочу сделать это изменение в точном месте контакта. Я хочу понять лучший способ сделать что-то подобное на более высоком уровне:Наблюдение за изменением в UIView во время анимации

- Должен ли я использовать animateWithDuration:... в обращении завершения в точке контакта? Другими словами, первая анимация работает до тех пор, пока она не ударит по этой координате x, а остальная часть анимации будет выполняться в обратном вызове завершения?

- Следует ли использовать наблюдатели NSNotification и наблюдать за изменениями в свойстве рамки? Насколько точным/гранулированным является это? Могу ли я отслеживать каждое изменение x? Должен ли я делать это в отдельном потоке?

Любые другие предложения приветствуются. Я ищу практикующую жизнь.

ответ

5

создайте NSTimer с некоторой задержкой и запустите определенный селектор после каждого простоя.
В этом методе проверьте рамку анимирующего представления и сравните ее с вашим сталкивающимся видом.

И убедитесь, что вы используете presentationLayer frame, потому что, если вы получаете доступ к view.frame во время анимации, он дает кадр назначения, который является постоянным через анимацию.

CGRect animationViewFrame= [[animationView.layer presentationLayer] frame]; 

Если вы не хотите, чтобы создать таймер, write a selector which calls itself after some delay задержку .have около .01 секунд.

РАЗЪЯСНЕНИЕ ->
Допустим, у вас есть представление, которое вы оживляющий свою позицию от (0,0) до (100,100) с длительностью 5secs. Предположим, вы реализовали KVO к раме этой точки зрения

При вызове animateWithDuration block, то положение точки зрения изменения непосредственно к (100,100), который является конечное значение, даже при том, что просмотреть движется с промежуточными значениями положения.

Итак, ваш KVO будет запущен один раз в момент начала анимации. Потому что слои имеют layer Tree и Presentation Tree. В то время как layer tree просто сохраняет значения назначения, а presentation Layer хранит промежуточные значения.
Когда вы получаете доступ к view.frame, он всегда дает значение кадра в layer tree, а не промежуточные кадры, которые он принимает.

Итак, вам нужно было использовать presentation Layer frame для получения промежуточных кадров.

Надеюсь, это поможет.

+1

Почему бы не наблюдатель работать здесь? – samonderous

+0

Спасибо за ответ, санту. Вот аналогичный вопрос ... http: //stackoverflow.com/q/41351175/294884 – Fattie

1

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

Для получения более подробной информации см. collision behaviour documentation.

8

Используйте CADisplayLink, поскольку он специально построен для этой цели. В документации говорится:

После того, как ссылка на изображение связана с циклом запуска, вызывается селектор цели, когда необходимо обновить содержимое экрана.

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

Это то, что я сделал:

let displayLink = CADisplayLink(target: self, selector: #selector(animationDidUpdate)) 
displayLink.frameInterval = 3 
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode) 

UIView.animateWithDuration(1.2, delay: 0.0, options: [.CurveEaseInOut], animations: { 
    self.viewGaugeGraph.frame.size.width = self.graphWidth 
    self.imageViewGraphCoin.center.x = self.graphWidth 
    }, completion: { (_) in 
     displayLink.invalidate() 
}) 

func animationDidUpdate(displayLink: CADisplayLink) { 
    let presentationLayer = self.viewGaugeGraph.layer.presentationLayer() as! CALayer 

    let newWidth = presentationLayer.bounds.width 

    switch newWidth { 
    case 0 ..< width * 0.3: 
     break 
    case width * 0.3 ..< width * 0.6: 
     // Color first mark 
     break 
    case width * 0.6 ..< width * 0.9: 
     // Color second mark 
     break 
    case width * 0.9 ... width: 
     // Color third mark 
     break 
    default: 
     fatalError("Invalid value observed. \(newWidth) cannot be bigger than \(width).") 
    } 
} 

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

Смежные вопросы