第三十九篇:IOS核心高级动画 Core Animation、Core Graphics

一、 CALayer < CAMediaTiming > 图层:

1. 图层属性及功能介绍:

1)contents :id 类型, 内容显示。
    在ARC环境下使用: = (__bridge id)image.CGImage;
    在MRC环境下使用:去掉(__bridge id)


2)contentsGravity:字符串型,图层的内容模式。功能与UIView 的contentMode用法相同;比如内容居中显示使用 kCAGravityCenter (值为字符串)。


3)contentsScale:浮点型,内容缩放。每个点与像素个数比例为 1:1。


4)contentsRect:NSRect型,在图层边框只显示寄存图的一个子域,犹如截图 。CGRect类型:不是按点来计算,是按比例计算。
 

5)contentsCenter:CGRect类型,定义一个固定的边框和一个可拉伸的区域。值是0~1(按比例)


6)poistion:CGPoint 类型,相对于父图层,自身的中心点。


7)anchorPoint:CGPoint 类型,锚点。
     锚点即指相对于自身而言的一个点,其范围在0~1之间 或 < 0 或 >1,表示x和y方向分别相对于自身的宽高比例,总与position点重合,而position是相对于父控制位置的点。
     当锚点被设置成相对于自身bounds的点后,就会平移对应的图层,使锚点与中心点重合,就算移动了但中心点是不会变的。


8)zPosition:CGFloat 类型,3D z 轴方向的距离。 可以明显改变屏幕上图层的显示顺序,但不能改变事件的传递顺序。


9)geometryFlipped:view.layer 的 geometryFlipped 属性 对subView的布局产生影响。设置YES,则subView.top 相对父view.bottom 了,也就形成了按水平中心线做了翻转。


CAMediaTiming 动画 协议 会在后面讲到


2. 图层方法有功能介绍:

1)- (void)renderInContext:(CGContextRef)ctx;   截图 功能。如下:
    // 1.截图
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    // 截取的图片
    UIImage * currentImage = UIGraphicsGetImageFromCurrentImageContext();
    // 在使用UIGraphicsBeginImageContextWithOptions函数一定要有对应的
    // UIGraphicsEndImageContext函数作为结尾,不然会有内存泄漏
    UIGraphicsEndImageContext() ;
  例如下代码:


#import "ViewController.h"

@interface ViewController ()

@property (nonatomic , strong) UIButton * transitionBtn ;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor redColor];
    self.transitionBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    self.transitionBtn.backgroundColor = [UIColor whiteColor];
    [self.transitionBtn setTitle:@"perform transition" forState:UIControlStateNormal];
    [self.transitionBtn addTarget:self action:@selector(performTransition) forControlEvents:UIControlEventTouchUpInside];
    self.transitionBtn.bounds = CGRectMake(0, 0, 100, 50);
    self.transitionBtn.center = self.view.center ;
    [self.view addSubview:self.transitionBtn];
    
    
}

-(void)performTransition
{
    // 1.截图
    UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    // 截取的图片
    UIImage * currentImage = UIGraphicsGetImageFromCurrentImageContext();
    // 在使用UIGraphicsBeginImageContextWithOptions函数一定要有对应的
    // UIGraphicsEndImageContext函数作为结尾,不然会有内存泄漏
    UIGraphicsEndImageContext() ;
    
    
    // 2.把截取的图添加到view上
    UIImageView * currentImageView = [[UIImageView alloc] initWithImage:currentImage];
    currentImageView.frame = self.view.bounds ;
    [self.view addSubview:currentImageView];
    
    // 3.随机改变view的背景色
    CGFloat red = arc4random() / (CGFloat)INT_MAX ;
    CGFloat greed = arc4random() / (CGFloat)INT_MAX ;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX ;
    self.view.backgroundColor = [UIColor colorWithRed:red green:greed blue:blue alpha:1.0];
    
    // 4.设置动画
    [UIView animateWithDuration:1.5 animations:^{
        
        CGAffineTransform transform = CGAffineTransformMakeScale(0.0001f, 0.0001f);
        transform = CGAffineTransformRotate(transform, M_PI_2) ;
        currentImageView.transform = transform ;
        currentImageView.alpha = 0.0 ;
        
    } completion:^(BOOL finished) {
        [currentImageView removeFromSuperview];
    }];

}


2)-(BOOL)containsPoint:(CGPoint)point; 
    功能:当在屏幕点击了图层的某个点point,如果要判断具体点击哪个图层,那么就需要用该方法断每个图层是否包含point点。


3)-(CALayer*)hitTest:(CGPoint)point; 
    功能:直接返回一个currentLayer 的 bounds 所对应的point点所在的最上层的layer对象,即返回真实被点击的layer图层。


4)- (CGPoint)convertPoint:(CGPoint)p fromLayer:(nullable CALayer *)L;
    功能:把 L 图层的bounds 所对应的 point 转成 当前 currentLayer 图层的 bounds 所对应的 point_1 位置;


5)- (CGPoint)convertPoint:(CGPoint)p toLayer:(nullable CALayer *)l;
    功能:把当前currentLayer图层所对应的point转成L图层的bounds所对应的pint_1位置。


6)-(void)layoutSublayerOfLayer:(CALayer *)layer;
     功能:当图层的bounds发生改变或图层的-setNeedsLayout方法被调用时,这个涵数将会被执行。但是不能像UIView的自动布局autorssizingMask 和 constraints属性做到自适应屏幕旋转。这也是为什么最好使用UIView而不单独用图层来构建应用程序的重要原因之一。


3.  边框阴影介绍。

     简介:图层的阴影继承自内容的外形(也就是layer.contents 或subLayer) ,而不是根据边界和角的半径来确定。

1)系统是根据层图的内容来设置阴影,而不是根据边框来设置阴影。
@ 属性设置(低性能)
    1.1 : shadowOpacity :透明度 。
    1.2 : shadowOffset :偏移量:水平和垂直。
    1.3 :shadowRadius :阴影的半径,越大显示越自然。
    1.4 :shadowColor :阴影颜色 。
    1.5 :shadowPath :设定一个巨型边框阴影。


2)例如:
   2.1 如果layer.backgroundColor 是clearColor且layer有一张图片,那么阴影的设置是沿那张图片的边框来设置。
   2.2 如果layer.backgroundColor 不是clearColor且layer有一张图片,那么阴影的设置是沿layer图层的边框来设置


3)性能高方法设置:设置图层的 shadowPaht 属性,这是给定了阴影显示的边框,不用系统去计算,直接显示某形状就OK了。
例如:
self.layer = [CALayer layer];
self.layer.frame = CGRectMake(100, 100, 100, 100);
[self.view.layer addSublayer:self.layer];
self.layer.shadowOpacity = 0.99 ;
// 边框的阴
self.layer.shadowRadius = 20 ;
// 通过 layer.shadowPath 属性来设置阴影范围,性能高
CGMutablePathRef pathRef = CGPathCreateMutable();
 // 矩形边阴影
CGPathAddRect(pathRef, NULL, self.layer.bounds);
self.layer.shadowPath = pathRef ;
CGPathRelease(pathRef);



4. 图层蒙板介绍。

        简介:设置图层的蒙板即 设置 图层的 mask 属性,类型是CALayer,类似一个子图层。

        解释:图层蒙板的Color属性无关紧要,真正重要的是图层的轮廓。mask 就像一个饼干切割机, mask 图层实心部分会被保留下来,其他则会被抛弃。

例子:// 显示的效果为:以image的形状对subView进行剪切
    self.subView = [[UIView alloc] init];
    self.subView.backgroundColor = [UIColor redColor];
    self.subView.frame = CGRectMake(0, 0, 300, 500);
    [self.view addSubview:self.subView];
    
    CALayer * maskLayer = [CALayer layer];
    UIImage * image = [UIImage imageNamed:@"icon_share"] ;
    maskLayer.frame = CGRectMake(150-image.size.width, 250-image.size.height, image.size.width, image.size.height) ;
    maskLayer.contents = (__bridge id __nullable)image.CGImage;
    maskLayer.contentsGravity = kCAGravityCenter ;
    maskLayer.contentsScale = [UIScreen mainScreen].scale ;
    
    self.subView.layer.mask = maskLayer ;



5. 拉伸过滤介绍。

        简介:相对的两个属性 ;一个是 minificationFilter 属性,用于缩小功能;另一个是 magnificationFilter 属性,用于放大功能。都是 NSString 类型,但都是枚举。设置不同的值有不同的效果,如下功能介绍 :

kCAFilterLinear(默认值):通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大时图片就模糊不清。

kCAFilterNearest:是一种比较武断的方法,就是取样最近的单像素点而不管其他的颜色,这样做非常快,也不会使图片模糊,但最明显的效果是会使得压缩图片更糟,图片放大后也显得块状或是马赛克严重。

kCAFilterTrilinear:与kCAFilterLinear非常相似,大部分情况下二者都看不出来,但比较而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果。效果显示清楚。



6. 仿射变换

       简介:在旋转时遵守一个规律,即:右手法则,大母指朝向原点,手握的方向即为旋转的方向。属性 layer.affineTransform 与 view.transform 功能一样。layer.transform 为3D效果。

1)transform 3D效果

        

 1.1:单独变换的一些方法 :

CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z);   // 以点(x,y,z)为向量旋转图层angle度

CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz);   // 对x、y和z方向上的点分别进行sx、sy和sz倍的缩放

CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz);    // 对layer的x、y和z方向分别平移tx、ty和tz。

1.2: 混合变换的一些方法:

CATransform3DRotate (CATransform3D t,CGFloat angle, CGFloat x,CGFloat y, CGFloat z);    // 在原有的变换基础上以点(x,y,z)为向量旋转图层angle度

CATransform3DScale (CATransform3D t, CGFloat sx,CGFloat sy, CGFloat sz);     // 在原有的基础上对x、y和z方向上的点分别进行sx、sy和sz倍的缩放

CATransform3DTranslation(CATransform3D t,Gloat tx, CGFloat ty, CGFloat tz);     // 在原有变换的基础上对layer的x、y和z方向分别平移tx、ty和tz

CATransform3DConcat (CATransform3D a, CATransform3D b);    // 在两个变换的基础上创建一个新的变换值

2)视图透视投影,立体感 

        简介:视图投影,使得在视觉上会产生错觉有立体感,结合上面的 3D 变换效果 会更好。

2.1 修改m34值使透视投影有立体感:

    2.1.1 、在现实生活中,当物体远离我们的时候,由于视角的原因看起来会变小,理论上远离我们的边要比靠近视角的边更短,但在实际上没有这样显示 ,而我们当前的视角是等距离的,也就是在3D变换中保持平行,和之前提到的仿射类似变换类似。所以为了修改在视觉上的差义性,就需要设置 CATransform3D 的透视效果中和一个元素:m34。m34用于按比例缩放X和Y的值来计算到底要离视图多远。

     2.1.2 、m34的值默认是0,我们可以通过设置 m34 为 -1.0 / D,D来应用透明效果,D代表想像中视角相机和屏幕之前的距离,以你素为单位。实现上我们大概估算就可以了,通常500~1000就已经很好了,D设置非常微的值会让它基本失真,越大的值会让它失去透明效果。( m34用于按比例缩放X和Y的值来计算到底要离视图多远 )。




2.2  3D变换后有立体感设置m34

        2.2.1 :  单视图投影立体感,如下

         

样例:self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"registerImageName"]];
    self.imageView.frame = CGRectMake(30, 50, 300, 600);
    [self.view addSubview:self.imageView];
    
    self.imageView.layer.shadowOpacity = 0.5 ;
    self.imageView.layer.shadowRadius = 4 ;
    self.imageView.layer.shadowOffset = CGSizeMake(0, 0);

    // 如果去掉transform3D.m34 = -1.0/500;代码,那么没有投影效果的立体感,只缩小了一点X和Y
    CATransform3D transform3D = CATransform3DIdentity ;
    transform3D.m34 = -1.0/500;
    transform3D = CATransform3DRotate(transform3D, M_PI_4, 1, 0, 0);
    self.imageView.layer.transform = transform3D ;


       2.2.2 :设置多个子视图投影立体感。只需设置 父视图的 superView.layer.sublayerTransform 属性,如下:

       只需要设置 superView.layer.sublayerTransform 子图层变换就会有立体感: 

        CATransform3D transform3D = CATransform3DIdentity ;

        transform3D.m34 = -1.0/500;

        self.view.layer.sublayerTransform = transform3D ;

         

        优点:灭点被设置在容器图层的中点,从而不需要再对子图层分别设置了。这意味着你可以随意使用posintion和frame来放置子图层,而不需要把它们放置在屏幕的中心,然后为了保证统一的灭点用变换来做平移。


样例: self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"registerImageName"]];
    self.imageView.frame = CGRectMake(50, 50, 100, 200);
    [self.view addSubview:self.imageView];
    
    self.imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"registerImageName"]];
    self.imageView2.frame = CGRectMake(150, 50, 100, 200);
    [self.view addSubview:self.imageView2];
    
    self.imageView.layer.shadowOpacity = 0.5 ;
    self.imageView.layer.shadowRadius = 4 ;
    self.imageView.layer.shadowOffset = CGSizeMake(0, 0);
    
    self.imageView2.layer.shadowOpacity = 0.5 ;
    self.imageView2.layer.shadowRadius = 4 ;
    self.imageView2.layer.shadowOffset = CGSizeMake(0, 0);

    // 如果去掉transform3D.m34 = -1.0/500;代码,那么没有投影效果的立体感,只缩小了一点X和Y
    CATransform3D transform3D = CATransform3DIdentity ;
    transform3D.m34 = -1.0/500;
    self.view.layer.sublayerTransform = transform3D ;
    
    self.imageView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.imageView2.layer.transform = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);


 2.3  doubleSided 属性

    表示:是否需要双面显示视图的内容,即背面是否要描绘显示出视图的内容。

例如  layer 旋转180 度 ,然后再设置 该属性后 显示效果。

2.3.1 : doubleSided = YES 在背面描绘显示出视图的内容,视图旋转了M_PI,所有的子视图也旋转了并可以从父视图背面看到,因为系统在背面描绘了内容。浪费CPU。


例子:self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"registerImageName"]];
    self.imageView.frame = CGRectMake(50, 50, 100, 200);
    [self.view addSubview:self.imageView];
    
    self.imageView.layer.shadowOpacity = 0.5 ;
    self.imageView.layer.shadowRadius = 4 ;
    self.imageView.layer.shadowOffset = CGSizeMake(0, 0);
    
       // 如果去掉transform3D.m34 = -1.0/500;代码,那么没有投影效果的立体感,只缩小了一点X和Y
//    CATransform3D transform3D = CATransform3DIdentity ;
//    transform3D.m34 = -1.0/500;
//    self.view.layer.sublayerTransform = transform3D ;
    
    self.imageView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
//    self.imageView.layer.doubleSided = NO ;


2.3.2 :  doubleSided = NO (默认值)不在背面描绘显示出视图的内容,视图旋转了M_PI,所有的子视图也旋转了,但不能从父视图背面看到,因为系统不会描绘看原来看不到的内容。不浪费CPU。(背面一片空白的效果)


例子:self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"registerImageName"]];
    self.imageView.frame = CGRectMake(50, 50, 100, 200);
    [self.view addSubview:self.imageView];
    
    self.imageView.layer.shadowOpacity = 0.5 ;
    self.imageView.layer.shadowRadius = 4 ;
    self.imageView.layer.shadowOffset = CGSizeMake(0, 0);
    
       // 如果去掉transform3D.m34 = -1.0/500;代码,那么没有投影效果的立体感,只缩小了一点X和Y
//    CATransform3D transform3D = CATransform3DIdentity ;
//    transform3D.m34 = -1.0/500;
//    self.view.layer.sublayerTransform = transform3D ;
    
    self.imageView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
    self.imageView.layer.doubleSided = NO ;


2.4 斜切视图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值