在Swift3中,KVO是UIView的alpha?

时间:2016-12-27 19:37:12

标签: uiview swift3 key-value-observing

使用这篇伟大帖子中的技术,对SwV3中的KVO值“很容易”......

https://stackoverflow.com/a/25219216/294884

我如何看待UIView的alpha?

目标:想象一个小视图的屏幕V.屏幕有一个大的桌面视图。每个单元格都有一个小视图CV。

我希望每个CV跟随 1 V的alpha,实际上是在V的alpha动画期间。

(我能想到的唯一真正的替代品是CADisplayLink细胞并轮询V的alpha,这种情况很糟糕。)

1 原因是什么?这是在单元格之间同步alpha变化的唯一方法。

注意正如Rob在下面解释的那样,实际上图层的alpha不会设置动画。 (它只是在动画开始时“立即”设置为新值。)实际上,您必须遵循表示层。这是一个逆向过程的例子,从你希望每次抽奖的地方拉出来

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 个答案:

答案 0 :(得分:9)

这不是KVO的理想用例。您可能更愿意转到正在更改alpha的代码并让它对其他视图进行必要的更新(或者构建一些更通用的接口;除了KVO之外的其他视图)。

另请注意,如果您正在处理动画,则alpha的KVO可能仅识别动画的启动,而不是观察动画期间飞行中的变化。 (通常使用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,那就不需要了。

但基于块的模式的优点在于:(a)当token超出范围时,观察者将被自动删除,因此不需要特殊的deinit例程; (b)observedView的可观察密钥现在是强类型的,避免了密钥中的简单印刷错误; (c)因为观察者与这种封闭有关,我们不再需要对观察者的背景进行检查,如果这不是我们的背景,请致电self