在 Swift3 中,KVO 是 UIView 的 alpha 吗?
In Swift3, KVO the alpha of a UIView?
它是 "easy" 到 Swift3 中的 KVO 值,使用这个伟大的技术 post...
如何 KVO UIView 的 alpha?
目标:想象一个小视图 V 的屏幕。屏幕有一个大 table 视图。每个单元格都有一个小视图CV。
我希望每个 CV 都遵循 1 V 的 alpha,实际上是在 V 的 alpha 动画期间。
(我能想到的唯一真正的替代方法是 CADisplayLink 单元格并轮询 V 的 alpha,这很糟糕。)
1这是什么原因?这是跨单元同步 alpha 更改的唯一方法。
注意 正如 Rob 在下面解释的那样,实际上 图层的 alpha 不会设置动画。 (它只是在动画开始时将 "instantly" 设置为新值。)事实上,您必须遵循表示层。这是一个相反过程的例子,从你想要的地方拉它每次抽奖
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
}
这不是 KVO 的理想用例。您可能更愿意转到正在更改 alpha
的代码,并让它对其他视图进行必要的更新(或者构建一些接口来更通用地执行此操作;KVO 以外的东西)。
另请注意,如果您处理的是动画,alpha
的 KVO 可能只会识别动画的启动,而不会观察动画飞行过程中的变化。 (这些变化通常用 CADisplayLink
中的 presentation
/presentationLayer
等捕获。)
话虽如此,可以观察alpha
属性。所以,在Swift 3中,只要定义context:
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)
}
注意,在Swift4中,这个过程被简化了一点。定义一个 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
如果这不是我们的上下文。
它是 "easy" 到 Swift3 中的 KVO 值,使用这个伟大的技术 post...
如何 KVO UIView 的 alpha?
目标:想象一个小视图 V 的屏幕。屏幕有一个大 table 视图。每个单元格都有一个小视图CV。
我希望每个 CV 都遵循 1 V 的 alpha,实际上是在 V 的 alpha 动画期间。
(我能想到的唯一真正的替代方法是 CADisplayLink 单元格并轮询 V 的 alpha,这很糟糕。)
1这是什么原因?这是跨单元同步 alpha 更改的唯一方法。
注意 正如 Rob 在下面解释的那样,实际上 图层的 alpha 不会设置动画。 (它只是在动画开始时将 "instantly" 设置为新值。)事实上,您必须遵循表示层。这是一个相反过程的例子,从你想要的地方拉它每次抽奖
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
}
这不是 KVO 的理想用例。您可能更愿意转到正在更改 alpha
的代码,并让它对其他视图进行必要的更新(或者构建一些接口来更通用地执行此操作;KVO 以外的东西)。
另请注意,如果您处理的是动画,alpha
的 KVO 可能只会识别动画的启动,而不会观察动画飞行过程中的变化。 (这些变化通常用 CADisplayLink
中的 presentation
/presentationLayer
等捕获。)
话虽如此,可以观察alpha
属性。所以,在Swift 3中,只要定义context:
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)
}
注意,在Swift4中,这个过程被简化了一点。定义一个 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
如果这不是我们的上下文。