Search code examples
swiftuiviewcalayerkey-value-observing

How can I observe changes to opacity of a UIView (possibly via its CALayer property?)


Title is the basic question. Trying to get notified when the opacity on a view(s layer) changes.

This is allowed...

addedView.addObserver(self, forKeyPath: #keyPath(isHidden), options: [.old, .new], context: nil)

But this doesn't compile...

addedView.layer.addObserver(self, forKeyPath: #keyPath(opacity), options: [.old, .new], context: nil)

Any ideas?


Solution

  • From the documentation:

    The property name must be a reference to a property that is available in the Objective-C runtime. [...] For example:

    // ...
    let c = SomeClass(someProperty: 12)
    let keyPath = #keyPath(SomeClass.someProperty)
    
    if let value = c.value(forKey: keyPath) {
        print(value)
    }
    

    When you use a key-path string expression within a class, you can refer to a property of that class by writing just the property name, without the class name.

    extension SomeClass {
        func getSomeKeyPath() -> String {
            return #keyPath(someProperty)
        }
    }
    print(keyPath == c.getSomeKeyPath())
    // Prints "true"
    

    So really, the property name in #keyPath(...) should be qualified in general. Unless the property is in the same class as the #keyPath expression, you should qualify the property name with its enclosing class name. This makes sense, because how else is the compiler going to know which isHidden property you mean?

    #keyPath(isHidden) just so happens to work because the class in which you are writing this in also happens to have a isHidden property (probably a UIView subclass?).

    You should do:

    #keyPath(CALayer.opacity)
    

    for opacity