iOS开发进阶 - 实现类似美颜相机的相机启动动画
程序员文章站
2022-03-23 14:13:03
最近在写一个相册的demo,偶尔看到了美拍的相机过载动画觉得很有意思,就想在我的相册demo中加入一个这种特效,下面把我的想法和实现过程给大家分享一下
先上效果图:(demo地址)
步骤分析...
最近在写一个相册的demo,偶尔看到了美拍的相机过载动画觉得很有意思,就想在我的相册demo中加入一个这种特效,下面把我的想法和实现过程给大家分享一下
先上效果图:(demo地址)
步骤分析
这个动效看起来很有特色但是实现起来是非常简单的,只需要用到calayer和
cashapelayer做为展示层,然后通过
cabasicanimation实现动画就行了~
用两个calayer来呈现启动的image 通过uibezierpath和cashapelayer来画出具有曲线的cashapelayer 然后将曲线的cashapelayer做为calayer的mask 最后通过cabasicanimation做一个简单的位移动画
先绘制上半部分的layer
先绘制上半部分的layer
/** 绘制上半部分的layer */ private func configtopshapelayer() { //绘制贝斯尔曲线 let topbezier:uibezierpath = uibezierpath() topbezier.movetopoint(cgpointmake(-1, -1)) topbezier.addlinetopoint(cgpointmake(bounds.width+1, -1)) topbezier.addcurvetopoint(cgpointmake(bounds.width/2.0+1, bounds.height/2.0+1), controlpoint1: cgpointmake(bounds.width+1, 0+1), controlpoint2: cgpointmake(343.5+1, 242.5+1)) topbezier.addcurvetopoint(cgpointmake(-1, bounds.height+2), controlpoint1: cgpointmake(31.5+2, 424.5+2), controlpoint2: cgpointmake(0+2, bounds.height+2)) topbezier.addlinetopoint(cgpointmake(-1, -1)) topbezier.closepath() //创建一个cashapelayer,将绘制的贝斯尔曲线的path给cashapelayer let topshape = cashapelayer() topshape.path = topbezier.cgpath //给toplayer设置contents为启动图 toplayer.contents = launchimage?.cgimage toplayer.frame = bounds layer.addsublayer(toplayer) //将绘制后的cashapelayer做为toplayer的mask toplayer.mask = topshape }
绘制后的结果是这样的:
然后以同样的原理绘制下半部分的layer
然后以同样的原理绘制下半部分的layer
/** 绘制下半部分的layer */ private func configbottomshapelayer() { //绘制贝斯尔曲线 let bottombezier:uibezierpath = uibezierpath() bottombezier.movetopoint(cgpointmake(bounds.width, 0)) bottombezier.addcurvetopoint(cgpointmake(bounds.width/2.0, bounds.height/2.0), controlpoint1: cgpointmake(bounds.width, 0), controlpoint2: cgpointmake(343.5, 242.5)) bottombezier.addcurvetopoint(cgpointmake(0, bounds.height), controlpoint1: cgpointmake(31.5, 424.5), controlpoint2: cgpointmake(0, bounds.height)) bottombezier.addlinetopoint(cgpointmake(bounds.width, bounds.height)) bottombezier.addlinetopoint(cgpointmake(bounds.width, 0)) bottombezier.closepath() //创建一个cashapelayer,将绘制的贝斯尔曲线的path给cashapelayer let bottomshape = cashapelayer() bottomshape.path = bottombezier.cgpath //给bottomlayer设置contents为启动图 bottomlayer.contents = launchimage?.cgimage bottomlayer.frame = bounds layer.addsublayer(bottomlayer) //将绘制后的cashapelayer做为bottomlayer的mask bottomlayer.mask = bottomshape }
这里注意的是画的贝斯尔曲线上半部分的要整体向下平移1到2个像素,为了防止贝斯尔曲线画曲线导致的锯齿效果,下面是下半部分完成后的效果图:
最后给两个layer一个位移动画
最后给两个layer一个位移动画
/** 展开的动画 */ func staranimation() { //创建一个cabasicanimation作用于calayer的anchorpoint let topanimation = cabasicanimation.init(keypath: "anchorpoint") //设置移动路径 topanimation.tovalue = nsvalue.init(cgpoint: cgpointmake(1, 1)) //动画时间 topanimation.duration = 0.6 //设置代理,方便完成动画后移除当前view topanimation.delegate = self //设置动画速度为匀速 topanimation.timingfunction = camediatimingfunction.init(name: kcamediatimingfunctionlinear) //设置动画结束后不移除点,保持移动后的位置 topanimation.removedoncompletion = false topanimation.fillmode = kcafillmodeforwards toplayer.addanimation(topanimation, forkey: "topanimation") //创建一个cabasicanimation作用于calayer的anchorpoint let bottomanimation = cabasicanimation.init(keypath: "anchorpoint") //设置移动路径 bottomanimation.tovalue = nsvalue.init(cgpoint: cgpointmake(0, 0)) //动画时间 bottomanimation.duration = 0.6 //设置动画速度为匀速 bottomanimation.timingfunction = camediatimingfunction.init(name: kcamediatimingfunctionlinear) //设置动画结束后不移除点,保持移动后的位置 bottomanimation.removedoncompletion = false bottomanimation.fillmode = kcafillmodeforwards bottomlayer.addanimation(bottomanimation, forkey: "topanimation") } /** 动画完成后移除当前view */ internal override func animationdidstop(anim: caanimation, finished flag: bool) { if flag { removefromsuperview() } }
这里为了方便观察,我将动画时间变长了,下面是完成后的效果图:
到这里这个动效就完成的差不多了,希望大家能学到东西,如果大家有更好的实现办法也可以给我提意见,我学习学习,谢谢大家观看,另外附加demo地址,喜欢的可以关注一下