视图和动画

2020-06-27  本文已影响0人  六横六竖亚

Core Animation

iOS系统的核心地位:应用内和应用间都会应用(多个程序间的手势切换)SpringBoard→BackBoard。

应用内的工作:Core Animation Pipeline管线(layout,display,preload,commit)

应用外的工作:提交到Render Server服务,反序列化构建渲染树GPU的工作:提交到GPU进行合成和渲染,输出到缓冲区

注1:代码只能控制CPU处理中的管线中的布局和显示两个阶段(通过setNeedLayout和setNeedDisplay)。

注1.1:setNeedDisplayInRect还能设置脏矩形来减少不必要的绘制。

注2:CPU偏计算;而图像的处理和渲染,用硬件会更快,因为GPU对图像计算进行了优化。

隐式动画

概念:更改一个CALayer的可做动画属性,Core Animation会执行一个隐式动画,平滑过渡到新值。动画的执行时间取决于事务的设置,动画的类型取决于图层行为。

实现:layer属性更改时会调用actionForKey方法,然后执行actionForLayer:forKey:代理方法(UIView禁用隐式动画的原理),如果没有实现代理,就查找属性-名称的actions映射字典和style字典,最后直接调defaultActionForKey。查找完actionForKey方法会返回一个CAAction做动画或NULL不做动画。

时机:由事务的管理机制控制。

注:UIView更改默认没有隐式动画,因为UIKit禁用了:UIView实现了CALayerDelegate的-actionForLayer:forKey方法,当属性的更改不在一个动画块中时,所有图层行为都会返回null,以此来禁用隐式动画。

显式动画 - CAAnimation

CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup

--动画属性

duration时长,repeatCount/repeatDuration重复次数/时间,beginTime,timingFunction(动画速度控制函数linear、easyIn/Out等),autoreverses结束后是否执行逆动画,from/toValue,removedOnCompletion + fillMode防止动画结束回到初始状态。

注:最好在动画完成后把layer的属性设置为最终状态,然后移除动画,否则会导致呈现树和逻辑树不符,造成混乱。

--虚拟属性

keyPath = "transform.scale .position .rotation .bgColor .opacity  .strokeEnd",不用创建CATransform3D指定动画变换。

--动画的取消

[layer removeAnimationForKey];

--动画的暂停

CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];

layer.speed = 0.0;

layer.timeOffset = pausedTime;

--动画的继续

CFTimeInterval pausedTime = [layer timeOffset];

layer.speed = 1.0;layer.

timeOffset = 0.0;

layer.beginTime = 0.0;

CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;

layer.beginTime = timeSincePause;

--动画的代理

animation.delegate = self; // 开始和结束动画的代理animationDidStart/DidStop等。

事务

事务是一系列属性动画集合,通过CATransaction管理事务组。

CATransaction没有属性和实例方法,只能通过+begin和+commit管理出入栈,+setAnimationDuration管理事务的动画时长和+animationDuration获取值(默认0.25),setCompletionBlock:可以设置事务完成后的回调。

事务的管理机制:每个RunLoop周期都会自动开始一个新的事务,把更改的属性收集起来做一次默认0.25s的隐式动画。

注:一般手动更改隐式动画的时间,需要新开事务避免影响别的动画(如屏幕旋转)。UIView的动画UIView的begin/commitAnimation底层原理也是设置了CATransactionUIView的animateWithDuration:animations:的Block动画方法其实也是内部自动调用了CATransaction的begin和commit,这样Block中的属性改变都会被事务所包含。

呈现树-presentationLayer

其实更改图层属性后,属性值立刻更新,但屏幕没有马上发生改变,因为它只是定义了图层动画结束后将要变化的外观,即图层树模型。但在设置新值后和新值生效前,屏幕渲染的过程中,当前显示的属性值,在某些场景下更有意义:1、在基于定时器的动画过程中获取当前图层的准确位置;2、在做动画的图层中,通过hitTest响应用户交互。(touchesBegan/Target-Action中,判断触摸点是否在presentationLayer内)

注:关键方法:locationInView / convertPoint->Point转化触摸点坐标系,presentationLayer -> CALayer获取呈现树中的视图位置,hitTest -> CALayer/ Contains-> Bool返回触摸的Layer / 判断触摸点是否在Layer上。

图片IO

imageWithContentsOfFile方法加载本地目录的图片文件,会在加载到内存之后才进行解码解压,所以会在绘制的时候影响性能,且不会进行内存缓存,适用于读取一次性大图的场景。

imageNamed可以避免延迟加载,会马上解压并加载到内存中缓存起来,但是只对assets中的资源有效。

强制解压和提前渲染:使用CGContext从上下文中绘制一个新的图片(直接绘制成CGImageRef位图)来代替(或绘制成一个点也会解压但不会节省绘制时间),优化了因解压增加的绘制时间,还可以丢弃解压后的图片节省内存,但需要更复杂的计算,CPU消耗总量增加。总结:使用CGContext异步重绘图片,得到解压缩后的位图。

UIView和CALayer

View持有Layer用于显示,View可以响应交互负责管理,View的属性大部分从Layer映射而来,UIView支持自动布局;Layer的delegate是View,动画会通知View,Layer更轻量级。提供View和layer两个平行的层级关系是为了职责分离,避免重复代码。

frame和bounds

frame:外部坐标,在父图层占据的位置

bounds:内部坐标本地坐标系,作用于子视图,左上角通常是{0, 0}(通过更改bounds实现简单的scrollView)

frame是一个虚拟属性,是根据bounds+position+transform计算而来;当对图层进行旋转或缩放时,frame实际是变换后,补齐的正矩形区域,即宽高可能和bounds不一致。

anchorPoint

锚点,UIView未暴露的属性,默认中心{0.5, 0.5},左上角{0, 0} 右下角{1, 1},小于0大于1将放置在图层外。UIView的Center和CALayer的Position属性加上锚点,才是图层的实际位置,所以图层锚点更改,frame会发生变化。

masksToBounds

Layer属性,设置为YES截取子图层实现圆角(cornerRadius);设为NO避免截取阴影(shadowOpacity,shadowColor,shadowOffset,shadowRadius,shadowPath-CGPath)。

mask蒙版

Layer属性,定义了父视图的可见区域,mask图层的颜色不重要,实心部分将会保留,其他隐藏

CGAffineTransform

UIView 仿射变换,仅支持2D变换:MakeRotation,Scale,Translation等。

CATransform3D

CALayer 3D变换,方法和仿射变换类似,加入zPosition形成4*4矩阵。

CAShapeLayer

基于CGPath路径创建CAShapeLayer矢量图形(非CG的Bitmap),bezierPathWithRoundedRect: byRoundingCorners: cornerRadii:可以单独指定每个角的圆角,作为蒙版为宿主层加圆角(mask)。

AVPlayerLayer

AVFoundation提供,和CA紧密结合,是CALayer的子类。AVPlayer + AVPlayerLayer简单的播放视频。

上一篇下一篇

猜你喜欢

热点阅读