CALayer 的 filters

CALayer 上有一个属性,一直以来大家都容易忽视,即:filters。而苹果官方文档上只给了 CIFilter 的示例,但事实上 CIFilter 设置进去后并没有效果,同时下方也指明了在 iOS 上不支持。(这里CIFilter 的完整列表)

@interface CALayer : NSObject <NSSecureCoding, CAMediaTiming>

/* An array of filters that will be applied to the contents of the
 * layer and its sublayers. Defaults to nil. Animatable. */

@property(nullable, copy) NSArray *filters;

@end

事实上 iOS 是支持实时滤镜的,不过要用到一个私有类 CAFilter。它的定义如下,长得像 CIFilter 的亲兄弟:

@interface CAFilter : NSObject <NSSecureCoding, NSCopying>
@property (readonly) NSString* type;
@property (copy) NSString* name;
@property (getter=isEnabled) BOOL enabled;
@property BOOL cachesInputImage;

+ (instancetype)filterWithType:(NSString *)type;
+ (instancetype)filterWithName:(NSString *)name;
+ (NSArray <NSString *> *)filterTypes;

- (instancetype)initWithType:(id)type;
- (instancetype)initWithName:(id)name;

- (void)setDefaults;
@end

目前支持的滤镜名(iOS 13)有以下这些:

  • multiplyColor
  • colorAdd 参数 CGColorRef: inputColor
  • colorSubtract 参数 CGColorRef: inputColor
  • colorMonochrome 参数 float: inputAmount
  • colorMatrix
  • colorHueRotate 参数 float: inputAngle (弧度)
  • colorSaturate 参数 float: inputAmount
  • colorBrightness 参数 float: inputAmount([-1, 1],0 为原始亮度)
  • colorContrast 参数 float: inputAmount
  • colorInvert 参数 BOOL: inputAmount
  • compressLuminance
  • meteor
  • luminanceToAlpha
  • bias
  • distanceField
  • gaussianBlur 参数 float: inputRadius, BOOL: inputNormalizeEdges
  • luminanceMap
  • luminanceCurveMap
  • curves
  • averageColor
  • lanczosResize
  • pageCurl
  • vibrantDark
  • vibrantLight
  • vibrantColorMatrix

前一段时间清明节,举国哀悼,为了向抗疫牺牲的烈士及遇难群众致哀,除了线下降半旗、鸣防空警报外,线上的 app、网页等也要求暂停,或配以黑白色,这是对 app 运营配置能力的一大考验。有了上面的 CAFilter 后,可以做到提前预埋 5 行代码将整个 app 变黑白色:

self.window.layer.filters = @[({  
    CIFilter *filter = [NSClassFromString(@"CAFilter") filterWithName:@"colorSaturate"];  // 看是 CIFilter,实际上是 CAFilter
    [filter setValue:@0 forKey:@"inputAmount"];
    filter;
})];

注意:此私有 API 有被拒风险