iOS开发码农的日常之iOS开发iOS技术资料

《Core Animation》-- CALayer基础属性及方

2017-06-02  本文已影响175人  妖精的菩萨

如图:UIView可以处理触摸事件,但CALayer是不支持交互的(不清楚具体的相应链的)。实际上这些背后关联的图层才是真正用来在屏幕上显示和做动画,UIView仅仅是对它的一个封装,提供了一些iOS类似于处理触摸的具体功能,以及Core Animation底层方法的高级接口。

<四个层级关系>:视图层级、图层树、呈现树和渲染树。

属性介绍

事实上,你真正要赋值的类型应该是CGImageRef,它是一个指向CGImage结构的指针。UIImage有一个CGImage属性,它返回一个"CGImageRef",如果你想把这个值直接赋值给CALayer的contents,那你将会得到一个编译错误。因为CGImageRef并不是一个真正的Cocoa对象,而是一个Core Foundation类型。可以通过bridged关键字转换。

@property(nullable, strong) id contents;
//对应UIView的contentMode.  
@property(copy) NSString *contentsGravity;
//决定了一个图层的坐标是否相对于父图层垂直翻转。是为了适配iOS和OS X两种不同坐标系的情况。
@property(getter=isGeometryFlipped) BOOL geometryFlipped;
//常用于做CATransform3D变换及更改图层的显示顺序。<不能改变事件传递的顺序>
@property CGFloat zPosition;
//在Z轴上描述图层位置的浮点类型
@property CGFloat anchorPointZ;

指定了anchorPoint相对于父图层的位置。

//对应UIView的center.
@property CGPoint position;

锚点,可以理解为固定图层的点。相对于自身坐标系,取值范围0~1,默认(0.5,0.5)。

@property CGPoint anchorPoint;

position和anchorPoint的换算公式:彻底理解position和anchorPoint

position.x = frame.origin.x + anchorPoint.x * bounds.size.width;  
position.y = frame.origin.y + anchorPoint.y * bounds.size.height;

属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数。当设置了contentsGravity属性会有所影响。

//如果contentsScale设置为1.0,将会以每个点1个像素绘制图片。并且把contentsGravity设置为kCAGravityCenter(这个值并不会拉伸图片),那将会有很明显的变化。
@property CGFloat contentsScale

属性允许我们在图层边框里显示寄宿图的一个子域,contentsRect不是按点来计算的,它使用了单位坐标,单位坐标指定在0到1之间,是一个相对值(像素和点就是绝对值)

@property CGRect contentsRect;

其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。

//单位坐标,定义的区域会被全面拉伸(也就是从四个方向进行放大或者缩小),所'侵占'的地方的视图也会进行相应的拉伸变换。
@property CGRect contentsCenter;
//等同于UIView的clipsToBounds.
@property BOOL masksToBounds;

是个CALayer类型,有和其他图层一样的绘制和布局属性。它类似于一个子图层,相对于父图层(即拥有该属性的图层)布局,但是它却不是一个普通的子图层。不同于那些绘制在父图层中的子图层,mask图层定义了父图层的部分可见区域。

@property(nullable, strong) CALayer *mask;
@property(copy) NSString *minificationFilter;//缩小:
@property(copy) NSString *magnificationFilter;//放大:

--值的介绍:

1。kCAFilterLinear:默认值,采用双线性滤波算法,它在大多数情况下都表现良好。双线性滤波算法通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大的时候图片就模糊不清了。

2。kCAFilterTrilinear:三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而�得到最后的结果。这不仅提高了性能,也避免了小概率因舍入错误引起的取样失灵的问题.

3。kCAFilterNearest:取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重。(不推荐)。

--总结:

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

为了启用shouldRasterize属性,我们设置了图层的rasterizationScale属性。默认情况下,所有图层拉伸都是1.0, 所以如果你使用了shouldRasterize属性,你就要确保你设置了rasterizationScale属性去匹配屏幕,以防止出现Retina屏幕像素化的问题。(info.plist文件中有个全局设置属性:UIViewGroupOpacity)

//组透明效果
@property BOOL shouldRasterize;

这里只提供了set和get方法。

- (CGAffineTransform)affineTransform;
- (void)setAffineTransform:(CGAffineTransform)m;

—栗子:

CGAffineTransform  affine = CGAffineTransformMakeRotation(M_PI_4);
blueLayer.affineTransform = affine;

代理

CALayer有一个可选的delegate属性,实现了CALayerDelegate协议,当CALayer需要一个内容特定的信息时,就会从协议中请求。CALayerDelegate是一个非正式协议,其实就是说没有CALayerDelegate @protocol可以让你在类里面引用啦。你只需要调用你想调用的方法,CALayer会帮你做剩下的。(delegate属性被声明为id类型,所有的代理方法都是可选的)。

- (void)displayLayer:(CALayerCALayer *)layer;
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

—栗子:

    CALayer * delegateLayer = [CALayer layer];
    [self.view.layer addSublayer:delegateLayer];
    delegateLayer.frame = CGRectMake(50, 100, 300, 400);
    delegateLayer.backgroundColor = [UIColor brownColor].CGColor;
    delegateLayer.delegate = self;//这里需遵循CALayerDelegate协议。

    [delegateLayer display];//这里需要显式地调用了-display。不同于UIView,当图层显示在屏幕上时,CALayer不会自动重绘它的内容。它把重绘的决定权交给了开发者。
- (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);
}

—效果:

95187B0D-764B-46CA-B26E-C4E835BD8D03.jpeg

—注意:

尽管我们没有用masksToBounds属性,绘制的那个圆仍然沿边界被裁剪了。这是因为当你使用CALayerDelegate绘制寄宿图的时候,并没有对超出边界外的内容提供绘制支持。

当UIView创建了它的宿主图层时,它就会自动地把图层的delegate设置为它自己,并提供了一个-displayLayer:的实现,那所有的问题就都没了。

当使用寄宿了视图的图层的时候,你也不必实现-displayLayer:-drawLayer:inContext:方法来绘制你的寄宿图。通常做法是实现UIView的-drawRect:方法,UIView就会帮你做完剩下的工作,包括在需要重绘的时候调用-display方法。

其它方法

+(Class)layerClass
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;//得到layer上的point的点相对于方法调用者的相对point。
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
- (BOOL)containsPoint:(CGPoint)p;
- (nullable CALayer *)hitTest:(CGPoint)p;

—栗子:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [[touches anyObject] locationInView:self.view];
    CALayer *layer = [self.layerView.layer hitTest:point];
    if (layer == self.blueLayer) {

    } else if (layer == self.layerView.layer) {

    }
}
上一篇下一篇

猜你喜欢

热点阅读