IOS开发之UI进阶(CALayer)

UIView需要显示到屏幕上时,会调用 drawrect方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了 UIView的显示

CALayer

  • CA:Core Animation(核心动画)
  • CALayerUIView的显示图层,通过UIViewlayer属性可以访问
  • CALayer负责视图中显示内容和动画
  • UIView负责监听和响应事件
@property(nonatomic,readonly,strong) CALayer *layer; 

CALayer的基本属性

	// 1.边框
	redView.layer.borderWidth = 10;//边框厚度
	redView.layer.borderColor = [UIColor redColor].CGColor;//边框颜色

	// 2.阴影 图层阴影并不总是方的,而是从图层内容的形状继承而来,可以是不规则的
	redView.layer.shadowOffset = CGSizeMake(100,100);//阴影偏移量 CGSizeZero
	redView.layer.shadowColor = [UIColor redColor].CGColor;//阴影颜色
	redView.layer.shadowRadius = 50;//阴影半径
	redView.layer.shadowOpacity = 1;//阴影不透明度为1

	// 3.圆角
	redView.layer.cornerRadius = 50;//边框厚度
	redView.layer.masksToBounds = YES;//超出范围不显示

	// 4.bounds
	redView.layer.bounds = CGRectMake(0,0,200,200);//直接设置wdxy
	redView.layer.frame = CGRectMake(0,0,200,200);//不建议设置wd
	redView.layer.position = CGPointMake(0,0)//设置中心 

	// 5.backgroundColor也是layer的属性
  • Viewlayer添加layer:可以实现一个View上面有多个颜色方块
	CALayer *layer = [[CALayer alloc] init];
	layer.backgroundColor = [UIColor redColor].CGColor;
	layer.position = CGPointMake(200,200);
	layer.bounds = CGRectMake(0,0,100,100);
	[self.view.layer addSublayer:layer];
  • layer自带隐式动画:带Animateble注释的属性,修改自带动画,透明度,大小,位置等

  • view的根layer是没有隐式动画

  • 禁用隐式动画(事务)

	// 都是类方法
	[CATransaction begin];// 开启事务
	[CATransaction setDisableActions:YES];// 禁止
	// 这里是生效的区域
	[CATransaction commit];// 提交事务

CALayer的锚点(定位点)

查看这个文章,详细介绍

CALayer的其他属性

  • contents :显示图层,可以设置图片
	layer.contents = (__bridge id)image.CGImage;
  • contentsGravity:设置对齐模型,对应UIViewcontentMode,但是它是一个NSString类型,而不是像对应的UIKit部分,那里面的值是枚举
	layer.contentsGravity = kCAGravityResizeAspect;
  • contentsScale:缩放比例
	// 获取图片对应的scale
	layer.contentsScale = image.scale;
	// 或者获取屏幕的scale
	layer.contentsScale = [UIScreen mainScreen].scale;
  • maskToBounds:对应UIViewclipsToBounds
	layer.maskToBounds = YES;
  • contentsRectCALayercontentsRect属性允许我们在图层边框里显示寄宿图的一个子域
	layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);

在这里插入图片描述

  • contentsCenter:它定义了一个固定的边框和一个在图层上可拉伸的区域
layer.contentsCenter = CGRectMake(0.25, 0.25, 0.5, 0.5);

在这里插入图片描述

  • shadowPath:用于自定义阴影图案,如果是一个矩形或者是圆,用CGPath会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath类会更合适
  //enable layer shadows
  self.layerView1.layer.shadowOpacity = 0.5f;
  self.layerView2.layer.shadowOpacity = 0.5f;

  //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);

在这里插入图片描述

  • shouldRasterize:组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,这样就没有透明度混合的问题了

在这里插入图片描述
在这里插入图片描述

	layer.shouldRasterize = YES;

CALayer绘制图案

  • 通过继承UIView并实现drawRect:方法来自定义绘制
  • 通过代理方法实现
// CALayerDelegate协议
// 当需要被重绘时,CALayer会请求它的代理给他一个寄宿图来显示。它通过调用下面这个方法做到的:
- (void)displayLayer:(CALayerCALayer *)layer;
// 趁着这个机会,如果代理想直接设置contents属性的话,它就可以这么做,不然没有别的方法可以调用了。如果代理不实现-displayLayer:方法,CALayer就会转而尝试调用下面这个方法:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
  //create sublayer
  CALayer *blueLayer = [CALayer layer];
  blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
  blueLayer.backgroundColor = [UIColor blueColor].CGColor;
  //set controller as layer delegate
  blueLayer.delegate = self;
  //ensure that layer backing image uses correct scale
  blueLayer.contentsScale = [UIScreen mainScreen].scale; //add layer to our view
  [self.layerView.layer addSublayer:blueLayer];
  //force layer to redraw
  [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);
}

在这里插入图片描述

Hit Testing

CALayer并不关心任何响应链事件,所以不能直接处理触摸事件或者手势。但是它有一系列的方法帮你处理事件:-containsPoint:-hitTest:

  • containsPoint:判断是否在内部,需要手动去转化对应的坐标系
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    //get touch position relative to main view
    CGPoint point = [[touches anyObject] locationInView:self.view];
    //convert point to the white layer's coordinates
    point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];
    //get layer using containsPoint:
    if ([self.layerView.layer containsPoint:point]) {
        //convert point to blueLayer’s coordinates
        point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];
        if ([self.blueLayer containsPoint:point]) {
        	NSLog(@"Inside Blue Layer");
        } else {
       	 	NSLog(@"Inside White Layer");
        }
    }
}
  • hitTest:不需要动去转化对应的坐标系,返回所在的layer或者nil

注意当调用图层的-hitTest:方法时,测算的顺序严格依赖于图层树当中的图层顺序(和UIView处理事件类似)。zPosition属性可以明显改变屏幕上图层的顺序,但不能改变事件传递的顺序,也意味着改变zPosition,将可能不能够检测到最前方的视图点击事件

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    //get touch position
    CGPoint point = [[touches anyObject] locationInView:self.view];
    //get touched layer
    CALayer *layer = [self.layerView.layer hitTest:point];
    //get layer using hitTest
    if (layer == self.blueLayer) {
		NSLog(@"Inside Blue Layer");
    } else if (layer == self.layerView.layer) {
		NSLog(@"Inside White Layer");
    }
}

CALayer图层蒙版在这里插入图片描述

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

  //apply mask to image layer
  self.imageView.layer.mask = maskLayer;

CALayer拉伸过滤

  • minificationFilter:缩小图片过滤器
  • magnificationFilter:放大图片过滤器
	// 双线性滤波算法
	kCAFilterLinear
	// 三线性滤波算法
	kCAFilterTrilinear
	// 最近过滤算法
	kCAFilterNearest
  • kCAFilterTrilinearkCAFilterLinear非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果
  • kCAFilterNearest是一种比较武断的方法。从名字不难看出,这个算法(也叫最近过滤)就是取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重

在这里插入图片描述
在这里插入图片描述

  • 对于没有斜线的小图来说,最近过滤算法要好很多。总的来说,对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特质以呈现更好的结果。但是对于大多数的图尤其是有很多斜线或是曲线轮廓的图片来说,最近过滤算法会导致更差的结果。换句话说,线性过滤保留了形状,最近过滤则保留了像素的差异

在这里插入图片描述

	// 默认的kCAFilterLinear
	view.layer.magnificationFilter = kCAFilterNearest;

CALayer的子类

进一步扩展使用Core Animation绘图的能力。

  • CAShapeLayer
  • CATextLayer
  • CATransformLayer
  • CAGradientLayer
  • CAReplicatorLayer
  • CAScrollLayer
  • CATiledLayer
  • CAEmitterLayer
  • CAEAGLLayer
  • AVPlayerLayer

参考资料

《iOS核心动画高级技巧》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本框架适用于 使用 NavigationController UITabBarController 的APP 框架QLSNavTab , GitHub地址:https://github.com/qianlishun/QLSNavTab 简介   -------准备工作------- 在AppDelegate中 设置一个控制器为主控制器 , 例如MainController - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; MainController *mainVc = [[MainController alloc]init]; // 设置根控制器 self.window.rootViewController = mainVc; // 设置为主控制器并可见 [self.window makeKeyAndVisible]; return YES; } 复制代码 在主控制器 中 复制代码 // 设置Nav背景色 self.navigationBackgroundColor = [UIColor colorWithRed:arc4random_uniform (256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]; self.childControllerAndIconArr = @[ /************第一个控制器配置信息*********************/ @{ VC_VIEWCONTROLLER : [[OneController alloc]init], //控制器对象 NORMAL_ICON : @"icon_classTable", //正常状态的Icon 名称 SELECTED_ICON : @"icon_classTable_selected", //选中状态的Icon 名称 TITLE : @"表" //Nav和Tab的标题 }, /************第二个控制器配置信息*********************/ @{ VC_VIEWCONTROLLER : [[TwoController alloc]init], NORMAL_ICON : @"icon_me", SELECTED_ICON : @"icon_me_selected", TITLE : @"通讯录" }, @{ /* 如果在此处使用storyboard,需要给storyboard设置storyboardID storyboardID 与 VC_STORYBOARD的value 同名 此处为Three */ VC_STORYBOARD :@"Three", NORMAL_ICON : @"icon_discover", SELECTED_ICON : @"icon_discover_selected", TITLE : @"发现" }, ];

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值