Core Animation 阅读随笔 第六章 - 专用图层

16/04/28 第六章 专用图层

CAShapeLayer

  1. CAShapeLayer是一个通过矢量图形绘制的图层子类,而非bitmap.
  2. 通过CAShapeLayer来绘制相比于Core Graphics而言优点在于:
    • 渲染快速, CAShapeLayer使用了硬件加速,绘制同一图形比Core Graphics快.
    • 搞笑使用内存,一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存. 矢量.
    • 不会被图层边界裁剪,一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉.
    • 不会出现像素化(矢量).当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。

-

创建一个CGPath

  1. 部分属性:
    • lineWith: 线宽,用点表示单位
    • lineCap: 线条结尾的样子
    • lineJoin: 线条之间的结合点的样子
  2. 可在同一图层绘制多个形状, 但只有一次机会设置属性,若需颜色不同,则要为每个形状准备一个图层.

-

圆角

  1. 通过UIBezierPath绘制自定义圆角个数的矩形:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //设置规则
    CGRect rect = CGRectMake(50, 50, 100, 100);
    CGSize radii = CGSizeMake(20, 20);

    UIRectCorner corners = UIRectCornerTopRight | UIRectCornerBottomRight | UIRectCornerBottomLeft;
    //创建被三儿路径
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:radii];

    // 设置ShapeLayer
    CAShapeLayer *shapeLayer = [CAShapeLayer alloc]init];
    shapeLayer.lineWidth = 3;
    shapeLayer.lineCap = kCALineCapRound;
    shapeLayer.lineJoin = kCALineJoinRound;
    shapeLayer.path = path.CGPath;

-

CATextLayer

  1. Core Animation提供了一个CALayer的子类CATextLayer,以图层的形式包含了UILabel几乎所有的绘制特性, 并额外提供了一些新的特性.
  2. 性能上,CATextLayerUILabel快很多.CATextLayer使用了Core Text.
  3. iOS6之前,UILabel通过WebKit来实现绘制?
  4. 用CATextLayer来实现一个UILabel:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
        @interface ViewController ()

    @property (nonatomic, weak) IBOutlet UIView *labelView;

    @end

    @implementation ViewController
    - (void)viewDidLoad
    {
    [super viewDidLoad];

    //创建TextLayer添加
    CATextLayer *textLayer = [CATextLayer layer];
    textLayer.frame = self.labelView.bounds;
    [self.labelView.layer addSublayer:textLayer];

    //设置字体颜色
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    //设置对齐方式
    textLayer.alignmentMode = kCAAlignmentJustified;
    textLayer.wrapped = YES;

    UIFont *font = [UIFont systemFontOfSize:15];

    //设置字体
    CFStringRef fontName = (__bridge CFStringRef)font.fontName;
    CGFontRef fontRef = CGFontCreateWithFontName(fontName);
    textLayer.font = fontRef;
    //设置字体大小
    textLayer.fontSize = font.pointSize;
    CGFontRelease(fontRef);

    //设置文本内容
    NSString *text = @"Lorem ipsum dolor sit amet, consectetur adipiscing \ elit. Quisque massa arcu, eleifend vel varius in, facilisis pulvinar \ leo. Nunc quis nunc at mauris pharetra condimentum ut ac neque. Nunc elementum, libero ut porttitor dictum, diam odio congue lacus, vel \ fringilla sapien diam at purus. Etiam suscipit pretium nunc sit amet \ lobortis";

    //赋值
    textLayer.string = text;
    }
    @end

    当这样设置后,显示会出现像素化,需要以当前屏幕的Scale来显示:
    textLayer.contentsScale = [UIScreen mainScreen].scale;

  5. CATextLayerfont属性为CFTypeRef类型, 可根据具体需求设置为CGFontRefCTFontRef.
  6. 字体大小由单独的fontSize决定, 因上述CTFontRefCGFontRef并不像UIFont一样包含点大小.
  7. CATextLayerstring属性为id类型,这样既可用NSString也可用富文本NSAttributedString了.

富文本

  1. 字符属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    字符属性可以应用于 attributed string 的文本中。

    NSString *const NSFontAttributeName;(字体)

    NSString *const NSParagraphStyleAttributeName;(段落)

    NSString *const NSForegroundColorAttributeName;(字体颜色)

    NSString *const NSBackgroundColorAttributeName;(字体背景色)

    NSString *const NSLigatureAttributeName;(连字符)

    NSString *const NSKernAttributeName;(字间距)

    NSString *const NSStrikethroughStyleAttributeName;(删除线)

    NSString *const NSUnderlineStyleAttributeName;(下划线)

    NSString *const NSStrokeColorAttributeName;(边线颜色)

    NSString *const NSStrokeWidthAttributeName;(边线宽度)

    NSString *const NSShadowAttributeName;(阴影)(横竖排版)

    NSString *const NSVerticalGlyphFormAttributeName;
  1. 常量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    1> NSFontAttributeName(字体)

    该属性所对应的值是一个 UIFont 对象。该属性用于改变一段文本的字体。如果不指定该属性,则默认为12-point Helvetica(Neue)。

    2> NSParagraphStyleAttributeName(段落)

    该属性所对应的值是一个 NSParagraphStyle 对象。该属性在一段文本上应用多个属性。如果不指定该属性,则默认为 NSParagraphStyle 的defaultParagraphStyle 方法返回的默认段落属性。

    3> NSForegroundColorAttributeName(字体颜色)

    该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的字体颜色。如果不指定该属性,则默认为黑色。

    4> NSBackgroundColorAttributeName(字体背景色)

    该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的背景颜色。如果不指定该属性,则默认无背景色。

    5> NSLigatureAttributeName(连字符)

    该属性所对应的值是一个 NSNumber 对象(整数)。连体字符是指某些连在一起的字符,它们采用单个的图元符号。0 表示没有连体字符。1 表示使用默认的连体字符。2表示使用所有连体符号。默认值为 1(注意,iOS 不支持值为 2)。

    6> NSKernAttributeName(字间距)

    该属性所对应的值是一个 NSNumber 对象(整数)。字母紧排指定了用于调整字距的像素点数。字母紧排的效果依赖于字体。值为 0 表示不使用字母紧排。默认值为0

    7> NSStrikethroughStyleAttributeName(删除线)

    该属性所对应的值是一个 NSNumber 对象(整数)。该值指定是否在文字上加上删除线,该值参考“Underline Style Attributes”。默认值是NSUnderlineStyleNone。

    8> NSUnderlineStyleAttributeName(下划线)

    该属性所对应的值是一个 NSNumber 对象(整数)。该值指定是否在文字上加上下划线,该值参考“Underline Style Attributes”。默认值是NSUnderlineStyleNone。

    9> NSStrokeColorAttributeName(边线颜色)

    该属性所对应的值是一个 UIColor 对象。如果该属性不指定(默认),则等同于 NSForegroundColorAttributeName。否则,指定为删除线或下划线颜色。更多细节见“Drawing attributedstrings that are both filled and stroked”。

    10> NSStrokeWidthAttributeName(边线宽度)

    该属性所对应的值是一个 NSNumber 对象(小数)。该值改变描边宽度(相对于字体size 的百分比)。默认为 0,即不改变。正数只改变描边宽度。负数同时改变文字的描边和填充宽度。例如,对于常见的空心字,这个值通常为3.0

    11> NSShadowAttributeName(阴影)

    该属性所对应的值是一个 NSShadow 对象。默认为 nil

    12> NSVerticalGlyphFormAttributeName(横竖排版)

    该属性所对应的值是一个 NSNumber 对象(整数)。0 表示横排文本。1 表示竖排文本。在 iOS 中,总是使用横排文本,0 以外的值都未定义。

UILabel的替代品

  1. 可以通过重写View的类方法 + (Class)layerClass来将UILabel替换成CATextLayer;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    #import "LayerLabel.h"
    #import <QuartzCore/QuartzCore.h>

    @implementation LayerLabel
    + (Class)layerClass
    {
    //this makes our label create a CATextLayer //instead of a regular CALayer for its backing layer
    return [CATextLayer class];
    }

    - (CATextLayer *)textLayer
    {
    return (CATextLayer *)self.layer;
    }

    - (void)setUp
    {
    //set defaults from UILabel settings
    self.text = self.text;
    self.textColor = self.textColor;
    self.font = self.font;

    //we should really derive these from the UILabel settings too
    //but that's complicated, so for now we'll just hard-code them
    [self textLayer].alignmentMode = kCAAlignmentJustified;

    [self textLayer].wrapped = YES;
    [self.layer display];
    }

    - (id)initWithFrame:(CGRect)frame
    {
    //called when creating label programmatically
    if (self = [super initWithFrame:frame]) {
    [self setUp];
    }
    return self;
    }

    - (void)awakeFromNib
    {
    //called when creating label using Interface Builder
    [self setUp];
    }

    - (void)setText:(NSString *)text
    {
    super.text = text;
    //set layer text
    [self textLayer].string = text;
    }

    - (void)setTextColor:(UIColor *)textColor
    {
    super.textColor = textColor;
    //set layer text color
    [self textLayer].foregroundColor = textColor.CGColor;
    }

    - (void)setFont:(UIFont *)font
    {
    super.font = font;
    //set layer font
    CFStringRef fontName = (__bridge CFStringRef)font.fontName;
    CGFontRef fontRef = CGFontCreateWithFontName(fontName);
    [self textLayer].font = fontRef;
    [self textLayer].fontSize = font.pointSize;

    CGFontRelease(fontRef);
    }
    @end