iOS 动画学习

gitbook地址

CALayer的几个属性和方法

contents:

// 你给contents赋的不是CGImage,那么你得到的图层将是空白的
layer.contents = (__bridge id)image.CGImage;

contentGravity:

// UIView有一个叫做contentMode,CALayer对应的属性叫做contentGravity

contentsScale:

// 寄宿图的像素尺寸和视图大小的比例
// 如果contentsScale设置为1.0,将会以每个点1个像素绘制图片,如果设置为2.0,则会以每个点2个像素绘制图片
layer.contentsScale = [UIScreen mainScreen].scale;

maskToBounds:

// UIView有一个叫做clipsToBounds,CALayer对应的属性叫做masksToBounds

contentsRect:

// contentsRect是{0, 0, 1, 1},按比例
// contentsRect{0,0,0.5,0.5} 则是左上角四分之一的图

contentsCenter:

// contentsCenter其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域
// 气泡拉伸,android的.9图片

Custom Drawing

  1. 通过继承UIView并实现-drawRect:方法来自定义绘制
  2. 实现CALayerDelegate:
/**
* 1.设置delegate
* 2. 调用display
* 3. 实现drawLayer:方法,方法内绘图
*/ 
  CALayer *blueLayer = [CALayer layer];
  blueLayer.delegate = self;
  [blueLayer display];
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
  //draw a thick red circle
  CGContextSetLineWidth(ctx, 10.0f);
  CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
  CGContextStrokeEllipseInRect(ctx, layer.bounds);
}

总结:
CALayerDelegate绘制:寄宿图不会自动重绘它的内容,决定权交给了开发者,通过调用display。
UIView的-drawRect绘制:UIView会帮你做完剩下的工作,无需手动调用display。

图层几何学

布局:

frame:代表了图层的外部坐标(也就是在父图层上占据的空间)
bounds:是内部坐标({0, 0}通常是图层的左上角)
center和position:都代表了相对于父图层anchorPoint所在的位置
注意:frame并不是一个非常清晰的属性,它其实是一个虚拟属性,是根据bounds,position和transform计算而来,改变frame的值同样会影响到他们当中的值
注意:当对图层做变换的时候,比如旋转或者缩放,frame实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说frame的宽高可能和bounds的宽高不再一致了,如图


86114FA1-BE8E-4CFE-BFC0-9D1974E48DAD.png
锚点(anchorPoint)(注意:center和position都代表了相对于父图层anchorPoint所在的位置)

默认位置:anchorPoint位于图层的中点
大小范围:{0,0}->{1,1} (contentsRect和contentsCenter属性类似)
锚点的作用:eg 实现一个🕙

@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIImageView *hourHand;
@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
@property (nonatomic, weak) IBOutlet UIImageView *secondHand;
@property (nonatomic, weak) NSTimer *timer;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //start timer
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
                  
    //set initial hand positions
    [self tick];
}

- (void)tick
{
    //convert time to hours, minutes and seconds
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
    CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
    //calculate hour hand angle //calculate minute hand angle
    CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
    //calculate second hand angle
    CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
    //rotate hands
    self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle);
    self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle);
    self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);
}
@end

效果图:

257239BF-BFF4-4B78-9C16-42EA2A7CFF7B.png

改变锚点之后:

- (void)viewDidLoad 
{
    [super viewDidLoad];
    // adjust anchor points
    self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f); 
    self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f); 
    self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
}

效果图:

FEBD2E9B-230C-4E7B-8C30-154BCA1DCCD7.png
坐标系

z坐标轴
zPosition:控制视图层级,越大的处于视图越上面,上面的视图会遮挡下面的视图(可以改变屏幕上图层的顺序,但不能改变事件传递的顺序)
anchorPointZ:z方向锚点

layer的方法:

containsPoint:接受一个在本图层坐标系下的CGPoint,如果这个点在图层frame范围内就返回YES
hitTest:返回图层本身,或者包含这个坐标点的叶子节点图层(测算的顺序严格依赖于图层树当中的图层顺序)

视觉效果

conrnerRadius: 圆角角度
masksToBounds: 裁剪
borderWidth:边框宽度
borderColor:边框颜色
shadowColor:阴影颜色
shadowOffset:阴影的方向和距离
shadowRadius:阴影模糊度
shadowPath:阴影的样式

// shadowPath使用:
 //create a square shadow
  CGMutablePathRef squarePath = CGPathCreateMutable();
  CGPathAddRect(squarePath, NULL, self.layerView1.bounds);
  self.layerView1.layer.shadowPath = squarePath; CGPathRelease(squarePath);

  //create a circular shadow
  CGMutablePathRef circlePath = CGPathCreateMutable();
  CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds);
  self.layerView2.layer.shadowPath = circlePath; CGPathRelease(circlePath);
 // 如果是一个矩形或者是圆,用CGPath会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath类会更合适

阴影的裁剪:(用一个额外的视图来解决阴影裁切的问题)
内层:设置masksToBounds = yes
外层:设置masksToBounds = no and shadow。

CALayer属性mask,蒙板原理实现不规则裁剪

//create mask layer
  CALayer *maskLayer = [CALayer layer];
  maskLayer.frame = self.layerView.bounds;
  UIImage *maskImage = [UIImage imageNamed:@"Cone.png"];
  maskLayer.contents = (__bridge id)maskImage.CGImage;

  //apply mask to image layer
  self.imageView.layer.mask = maskLayer;
CB9B3017-2752-46F8-922D-2874BA055958.png

CALayer蒙板图层真正厉害的地方在于蒙板图不局限于静态图。任何有图层构成的都可以作为mask属性,这意味着你的蒙板可以通过代码甚至是动画实时生成。

layer拉伸与裁剪

layer.magnificationFilter
// 图片拉伸算法
kCAFilterLinear
kCAFilterNearest
kCAFilterTrilinear

//set up digit views
  for (UIView *view in self.digitViews) {
    //set contents
    view.layer.contents = (__bridge id)digits.CGImage;
    view.layer.contentsRect = CGRectMake(0, 0, 0.1, 1.0);
    view.layer.contentsGravity = kCAGravityResizeAspect;
  }

组透明

CALayer属性:opacity(等同UIView的alpha的属性来确定视图的透明度。)
CALayer属性:shouldRasterize(来实现组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,然后再透明)

 //enable rasterization for the translucent button
  button2.layer.shouldRasterize = YES;
  button2.layer.rasterizationScale = [UIScreen mainScreen].scale;
// 设置rasterizationScale属性去匹配屏幕,以防止出现Retina屏幕像素化的问题

变换


专用图层

CAShapeLayer:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容