在自定义属性更改时重绘自定义 CALayer 子类

Posted

技术标签:

【中文标题】在自定义属性更改时重绘自定义 CALayer 子类【英文标题】:Redrawing custom CALayer subclass on custom property change 【发布时间】:2012-05-19 08:48:28 【问题描述】:

我正在尝试构建一个绘制文本的特殊图层。这个TWFlapLayer 有一个属性字符串作为属性:

TWFlapLayer.h:

@interface TWFlapLayer : CALayer
@property(nonatomic, strong) __attribute__((NSObject)) CFAttributedStringRef attrString;
@end

并在TWFlapLayer.m中合成:

@implementation TWFlapLayer

@synthesize attrString = _attrString;

/* overwrite method to redraw the layer if the string changed */

+ (BOOL)needsDisplayForKey:(NSString *)key

    if ([key isEqualToString:@"attrString"])
        return YES;
     else 
        return NO;
    


- (void)drawInContext:(CGContextRef)ctx

    NSLog(@"%s: %@",__FUNCTION__,self.attrString);
    if (self.attrString == NULL) return;
    /* my custom drawing code */

我的意图是,如果使用合成的 setter 方法更改了 attrString 属性,则使用我的自定义绘图方法自动重绘图层。但是,从放置在 drawInContext: 方法中的 NSLog 语句中,我看到该图层是 not 重绘的。

通过在 needsDisplayForKey 方法中放置一个断点,我确保它在询问 attrString 键时返回 YES。

我现在正在像这样更改 attrString

// self.frontString is a NSAttributedString* that is why I need the toll-free bridging
self.frontLayer.attrString = (__bridge CFAttributedStringRef) self.frontString;

//should not be necessary, but without it the drawInContext method is not called
[self.frontLayer setNeedsDisplay]; // <-- why is this still needed?

我在 CALayer 头文件中查找了 needsDisplayForKey 的类方法定义,但在我看来这是我想使用的方法,还是我在这里遗漏了重要的一点?

来自CALayer.h

/* Method for subclasses to override. Returning true for a given
 * property causes the layer's contents to be redrawn when the property
 * is changed (including when changed by an animation attached to the
 * layer). The default implementation returns NO. Subclasses should
 * call super for properties defined by the superclass. (For example,
 * do not try to return YES for properties implemented by CALayer,
 * doing will have undefined results.) */

+ (BOOL)needsDisplayForKey:(NSString *)key;

总结

当自定义属性 attrString 更改并由needsDisplayForKey: 标记时,为什么我的图层不重绘?

【问题讨论】:

【参考方案1】:

CALayer.h 还说:

/* CALayer implements the standard NSKeyValueCoding protocol for all
 * Objective C properties defined by the class and its subclasses. It
 * dynamically implements missing accessor methods for properties
 * declared by subclasses.

显然needsDisplayForKey: 机制依赖于 CALayer 的动态实现的访问器方法。所以,改变这个:

@synthesize attrString = _attrString;

@dynamic attrString;

【讨论】:

太棒了!那成功了。 CALayer.h 真的是一个巨大的文件,错过了这一点有点尴尬。 @kurt-revis 我有类似的问题,@dynamic 工作正常,谢谢。但是你能解释一下为什么我没有进行初始渲染,即使我在-(id)init 方法中设置了初始值。 needsDisplayForKey 根本不会在init 中触发。

以上是关于在自定义属性更改时重绘自定义 CALayer 子类的主要内容,如果未能解决你的问题,请参考以下文章

当设备方向更改 SWIFT 5 时重绘自定义 UIVIEW

将 CALayer 添加到 UIView 并能够在方向更改时重绘

在自定义 UITableViewCell 中更改 UILabel 的颜色

出队后,CALayer 在自定义 UITableViewCell NIB 上消失

在缩放/变换上强制重绘 UIView 或 CALayer

如何在更改其边界的动画期间强制重绘 CALayer