'Unable to animate a Swift custom property with animator() [ OSX ]
I am trying to animate a custom property using animator() in swift for Objective-C. But I am getting a EXC_BAD_ACCESS exception when I try and set the property through the animator. In a previous application, written in Objective-C, I had used the same idea and it worked.
Here is the class in Swift:
import Cocoa
import QuartzCore
@IBDesignable
class StopPlayButton: NSView {
//This is the property that I am trying to animate
@IBInspectable
var playButtonShapeInterval:Float = 1.0 {
didSet{
self.needsDisplay = true
}
}
@IBInspectable
var isPressed:Bool = false{
didSet{
self.needsDisplay = true
}
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
StyleKit.drawPlayStopButton(playButtonShapeInterval: CGFloat(self.playButtonShapeInterval), buttonPressed: self.isPressed)
}
func toggle(){
NSAnimationContext.beginGrouping()
NSAnimationContext.currentContext().duration = 1.0;
NSAnimationContext.currentContext().timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut);
if self.playButtonShapeInterval == 0 {
self.animator().playButtonShapeInterval = 1.0
}
else{
self.animator().playButtonShapeInterval = 0.0//exception happending here...
}
NSAnimationContext.endGrouping()
}
override static func defaultAnimationForKey(key: String) -> AnyObject?{
if key == "playButtonShapeInterval" {
return CABasicAnimation()
}
return super.defaultAnimationForKey(key)
}
}
Note, if I change the property name to playButtonShapeInterval to alphaValue, then the alpha animation works.
Below is the above code ported to Objective-C, doing what I want. I am not sure what is different:
//StopPlayButton.m
#import "StopPlayButton.h"
#import "StyleKit.h"
#import <QuartzCore/QuartzCore.h>
@implementation StopPlayButton
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSLog(@"This is the interval: %f", self.playButtonShapeInterval);
[StyleKit drawPlayStopButtonWithPlayButtonShapeInterval:self.playButtonShapeInterval buttonPressed:self.playButtonPressed];
}
-(void)setPlayButtonShapeInterval:(float)playButtonShapeInterval{
if(playButtonShapeInterval != _playButtonShapeInterval){
_playButtonShapeInterval = playButtonShapeInterval;
[self setNeedsDisplay:YES];
}
}
-(void)toggle{
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5];
[[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
if(self.playButtonShapeInterval == 0){
self.animator.playButtonShapeInterval = 1;
}
else{
self.animator.playButtonShapeInterval = 0;
}
[NSAnimationContext endGrouping];
}
+(id)defaultAnimationForKey:(NSString *)key{
if ([key isEqualToString:@"playButtonShapeInterval"]) {
return [CABasicAnimation animation];
}
return [super defaultAnimationForKey:key];
}
@end
//StopPlayButton.h
#import <Cocoa/Cocoa.h>
@interface StopPlayButton : NSView
@property (nonatomic) BOOL playButtonPressed;
@property (nonatomic) float playButtonShapeInterval;
-(void)toggle;
@end
Solution 1:[1]
I met the same problem and fixed it by declaring the custom property as 'dynamic'. I believe it's required by KVO.
dynamic var playButtonShapeInterval:Float = 1.0 {
didSet{
self.needsDisplay = true
}
}
Solution 2:[2]
In Swift 5, you need this:
@objc class YourView: NSClipView {
@objc dynamic var yourAnimatableProperty = CGFloat(1)
override static func defaultAnimation(forKey key: NSAnimatablePropertyKey) -> Any? {
if key == "yourAnimatableProperty" {
return CABasicAnimation()
}
return super.defaultAnimation(forKey: key)
}
...
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Wevah |
