В Swift3, KVO - альфа UIView?

Это "легко" для KVO значение в Swift3, используя технику в этой большой записи...

qaru.site/info/32820/...

Как сделать KVO альфа UIView?

Цель: представить экран с небольшим видом V. Экран имеет большой вид стола. Каждая ячейка имеет небольшое представление CV.

Я хочу, чтобы каждое CV следовало за 1 альфой V, фактически во время анимации альфа V.

(Единственная реальная альтернатива, о которой я могу думать, - это CADisplayLink для ячеек и опрос альфа V, какой отстой.)


1 Причина этого? Это единственный способ синхронизации альфа-изменений по ячейкам.


Примечание Как объясняет Роб ниже, на самом деле альфа слоя не анимируется. (Он просто устанавливает "мгновенно" новое значение в начале анимации.) Фактически вы должны следить за уровнем презентации. Вот пример обратного процесса, потянув его из того места, где вы хотите каждую ничью

let d = CADisplayLink(target: self, selector: #selector(ThisClassName.updateAlpha))
d.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)

func updateAlpha() {
  let a = leader.layer.presentation()?.value(forKey: "opacity") as! CGFloat
  follower.alpha = a
  }

Ответ 1

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

Также обратите внимание, что если вы имеете дело с анимацией, KVO alpha может идентифицировать только начало анимации, не наблюдая изменений в середине полета во время анимации. (Такие изменения обычно фиксируются с помощью presentation/presentationLayer в CADisplayLink или т.п.)

Сказав это, да, вы можете наблюдать свойство alpha. Итак, в Swift 3 просто определите контекст:

private var observerContext = 0  

Затем добавьте наблюдателя:

observedView.addObserver(self, forKeyPath: "alpha", options: .new, context: &observerContext)

а затем выполните ваш наблюдатель:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard context == &observerContext else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }

    // do what you want here
}

Примечание. Не забудьте удалить наблюдателя. Например, вы можете сделать это в deinit:

deinit {
    observedView.removeObserver(self, forKeyPath: "alpha", context: &observerContext)
}

Примечание. В Swift 4 этот процесс немного упрощается. Определите свойство token, чтобы отслеживать наблюдателя:

private var token: NSKeyValueObservation?

И затем соблюдайте свойство alpha:

token = observedView.observe(\.alpha) { [weak self] object, change in
    // do something
}

Обратите внимание на использование [weak self], чтобы обеспечить закрытие не вызывает сильный опорный цикл. Очевидно, что если вы не ссылаетесь на self в этом закрытии, это не требуется.

Но достоинством шаблона на основе блоков является то, что (а), когда token выпадает из области видимости, наблюдатель автоматически удаляется, поэтому никакой специальной процедуры deinit не требуется; (b) наблюдаемые клавиши для observedView теперь строго типизированы, избегая простых типографских ошибок в ключах; и (c) поскольку наблюдатель связан с этим закрытием, нам больше не нужно выполнять эту проверку контекста наблюдателя и вызывать self, если это не наш контекст.