【问题标题】:Animating a custom property of CALayer subclass动画 CALayer 子类的自定义属性
【发布时间】:2011-01-24 14:54:16
【问题描述】:

我有一个 CALayer 子类 MyLayer,它有一个名为 myInt 的 NSInteger 属性。我真的很想通过 CABasicAnimation 为这个属性设置动画,但似乎 CABasicAnimation 只适用于所谓的“动画”属性(边界、位置等)。有什么我可以覆盖的东西来使我的自定义 myInt 属性具有动画效果吗?

【问题讨论】:

  • 尝试将该属性设为float

标签: iphone core-animation calayer


【解决方案1】:

是的,这是可能的(不过,我相信只有在最新的 Core Animation 版本中,即 iPhone 3.0+ 和 OS X 10.6+)。

  1. 使您的属性动态化,以便 CA 为您实现访问器:

    @dynamic myInt;
    
  2. 告诉图层属性的变化需要重绘:

    + (BOOL)needsDisplayForKey:(NSString*)key {
        if ([key isEqualToString:@"myInt"]) {
            return YES;
        } else {
            return [super needsDisplayForKey:key];
        }
    }
    
  3. 在您的drawInContext: 方法中使用myInt 的值。现在,当您为myInt 设置动画时,Core Animation 将为动画的每一步插入值并反复要求图层自行绘制。

  4. 如果您还想为此属性启用隐式动画,请同时覆盖 actionForKey:

【讨论】:

  • 谢谢!这让我非常接近解决方案,我可以品尝它! -drawInContext: 在正确插入 myInt 的情况下被调用多次。不幸的是 CGContextDrawImage() 在动画运行时不再起作用。我填充的矩形或我描边的路径都正确绘制,但是通常由 CGContextDrawImage() 绘制的图像会消失,直到动画结束,就好像从未调用过 CGContextDrawImage() 一样。我很困惑。有什么想法吗?
  • 没关系。你的回复仍然是我在 Stack Overflow 上看到的最好的书面答案之一 :)
  • 亲爱的未来谷歌员工:CGContextDrawImage() 没有绘图,因为我将它的 CGImageRef 存储在 ivar 中。当 CoreAnimation 生成其多个表示层(或其他)时,它不会复制 ivars,仅复制 KVC 值。将我的图像存储在 UIImage 中,然后 [self setValue:myUIImage forKey:@"image"] 以供以后在 -drawInContext: 中检索:成功了。
  • @dynamic myInt 对我不起作用;我必须 @synthesize myInt 才能让它工作。
  • @jemmons 在这种情况下,正确的解决方案是在 initWithLayer 中复制这些属性:
【解决方案2】:

有一种方法可以保留自定义 CALayer 子类的 iVar。您覆盖 initWithLayer:,该方法被调用以创建自定义图层的副本。例如,如果您要在图层中创建名为“角度”的自定义属性,则可以使用以下代码:

@implementation AngledLayer
@synthesize angle = _angle

// Tell Core Animation that this key should be animated
+ (BOOL) needsDisplayForKey:(NSString *)key
{
    if ([key isEqualToString:@"angle"]) return YES;
    return [super needsDisplayForKey:key];
}


// Make sure that, when the layer is copied, so is the custom ivar
- (id) initWithLayer:(id)layer
{
    self = [super initWithLayer:layer];
    if (self) {
        AngledLayer *angledVersion = (AngledLayer *)layer;
        self.angle = angledVersion.angle;
    }
    return self;
}

鲍勃是你的叔叔!请注意,您不能将此对象与隐式动画一起使用,您还必须覆盖 actionForKey: 方法。

【讨论】:

  • 这对我不起作用。在initWithLayer 内部,图层始终具有属性的起始值,即使在制作动画时也是如此。 setter 在其他地方被调用。
  • 我看到的和 yourfriendzak 一样。虽然 initWithLayer 和 needsDisplayForkey 的组合允许动画发生,但一旦它结束,图层就会回到它的起始值。我仍在寻找解决方案。
  • 好吧,看来我没有意识到 @dynamic 会导致设置器自动设置动画。但是如果由于某种原因你需要做更多的事情,你可能需要创建自己的设置器,它有自己的动画块,这样你就可以在动画发生之前改变你的图层属性。见link
【解决方案3】:

斯威夫特版本

// Custom property
@NSManaged public var progress: CGFloat
    
open override class func needsDisplay(forKey key: String) -> Bool {
    if key == "progress" {
        return true
    }
    return super.needsDisplay(forKey: key)
}

【讨论】:

    猜你喜欢
    • 2011-03-11
    • 2015-08-13
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    • 2011-05-06
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多