从CRNetworkButton学习CALayer与CAShapeLayer:iOS自定义控件动画开发实战
从CRNetworkButton学习CALayer与CAShapeLayeriOS自定义控件动画开发实战【免费下载链接】CRNetworkButtonSend Button for iOS项目地址: https://gitcode.com/gh_mirrors/cr/CRNetworkButton很多iOS开发者都遇到过这样的场景写一个带加载动画的按钮绞尽脑汁却不知从何下手。其实CALayer与CAShapeLayer正是破解iOS自定义控件动画的关键。本文以开源组件CRNetworkButton一个点击后自动展示加载、进度、成功/失败状态的iOS发送按钮为例带你从零拆解CALayer与CAShapeLayer的实战用法手把手完成一次iOS自定义控件动画开发之旅。CRNetworkButton是什么自带加载动画的iOS发送按钮CRNetworkButton 是 Cleveroad 团队开源的 UIButton 子类核心能力只有一个当用户点击发送/提交按钮发起网络请求时按钮本身会变成动画反馈器——矩形按钮收缩成圆形、内部出现旋转的加载线条或环形进度条请求结束后再弹出对勾成功或叉号失败并弹回原尺寸。整个过程一气呵成让用户对网络状态所见即所得。它最值得学习的地方是全部动画都基于CALayer体系完成完全不依赖 UIKit 的动画 API。核心代码全部封装在 CRNetworkButton.swift 这一个文件里约 800 行非常适合作为 iOS 自定义控件动画的入门教材。认识CALayer与CAShapeLayeriOS动画的基石在拆解之前先花一分钟理清概念CALayer承载内容与绘制的底层对象负责bounds、position、backgroundColor、cornerRadius等属性的渲染动画就是对这些属性的插值。CAShapeLayerCALayer 的子类专门用path路径来绘图配合strokeColor、fillColor、lineWidth、strokeEnd等属性可以轻松画出圆弧、线条和任意矢量图形。记住一句心法能画出来的图形就能动起来。CRNetworkButton 正是把这句话发挥到了极致。动画状态机iOS按钮动画的导演指挥复杂的按钮动画最怕失控CRNetworkButton 用四个状态把动画串成一条清晰的流水线状态含义触发方式ready初始状态显示Go默认loading加载中按钮变圆形旋转动画startAnimate()finishing结束过渡绘制对勾/叉号stopAnimate()/stopByError()finished完成状态显示Done动画自动完成每次状态切换都会调用handleCRState分发对应的动画组配合DispatchGroup确保上一段动画播完、下一段动画才开始。这种状态机动画组的设计思路值得你在任何 iOS 自定义控件动画中复用。实战一用CAShapeLayer绘制旋转加载动画加载状态的核心视觉是一圈旋转的线段代码实现只分两步。第一步用 UIBezierPath 画一段圆弧作为 CAShapeLayer 的路径let line CAShapeLayer() line.path UIBezierPath(arcCenter: center, radius: r, startAngle: angle, endAngle: angle dotLength, clockwise: true).cgPath line.lineCap kCALineCapRound line.strokeColor crDotColor.cgColor第二步给图层加一个无限旋转的 transform 动画let rotation CABasicAnimation(keyPath: transform.rotation.z) rotation.byValue 2 * Double.pi rotation.duration velocity rotation.repeatCount .infinity line.add(rotation, forKey: lineRotation)两条核心代码一个可无限旋转的 iOS 加载动画就诞生了。把linesCount从 1 调到 4还会得到四叶草般不同的加载效果可玩性极高。实战二strokeEnd实现环形进度动画如果需要展示真实的下载/上传进度CRNetworkButton 提供了progressMode。它的实现堪称一行代码的艺术layer.strokeEnd 0 // 起点弧线长度为 0 // ... 后续更新进度只需 progressLayer.strokeEnd progressCAShapeLayer.strokeEnd表示路径描边的完成比例0~1动画系统会自动在旧值和新值之间做平滑过渡。所以示例代码里用定时器不断更新进度ViewController.swift 中只需要调用updateProgress(_:)一条环形进度条就活了。实战三UIBezierPath绘制对勾与错误叉号请求结束按钮要画出结果。成功画对勾、失败画叉号靠的还是 UIBezierPath CAShapeLayerlet path UIBezierPath() path.move(to: startPoint) path.addLine(to: midPoint) path.addLine(to: endPoint) // 三段连起来就是一个对勾路径画好后用CAKeyframeAnimation控制opacity在 0→1→0 之间变化就形成了对勾亮起又淡出的呼吸感。这段几何计算逻辑就在pathForMark()与pathForCrossMark()两个方法里想改成点赞心形之类的图标也只需替换路径这就是 iOS 自定义控件动画的高度可扩展性。实战四CAKeyframeAnimation实现弹性回弹最后一步按钮要从圆形弹回矩形。CRNetworkButton 没有用单调的线性动画而是构造了一个三段式关键帧let proportions: [CGFloat] [circleW/startW, 1.2, 1]按钮先回到原始宽度再放大到 1.2 倍最后收缩到 100%配合keyTimes控制节奏一个俏皮的弹性回弹就完成了。这种过冲再回正的手法是让 iOS 动画显得高级的常用技巧。在Storyboard中零代码配置按钮属性CRNetworkButton 全类标注了IBDesignable与IBInspectable这意味着你在 Storyboard 里就能实时看到并修改动画参数线条数量、旋转速度、对勾颜色、错误颜色、进度模式、是否点击自动开启动画……全部可视化拖拽配置对新手极其友好也是学习自定义控件可视化编程的绝佳范例。三步接入你的iOS项目第一步CocoaPods 安装。在 Podfile 中加入一行pod CRNetworkButton然后执行pod install。如果想本地跑示例工程也可以把仓库克隆下来git clone https://gitcode.com/gh_mirrors/cr/CRNetworkButton进入Example目录后同样执行pod install即可。第二步导入并连线import CRNetworkButton IBOutlet weak var sendButton: CRNetworkButton!第三步调用动画接口。配合模拟网络请求的 FakeNetworkManager.swift几行代码就能得到完整的成功/失败反馈FakeNetworkManager.performRequest(withSuccess: { _ in sendButton.stopAnimate() // 成功对勾回弹 }) { _ in sendButton.stopByError() // 失败叉号红色错误态 }小结你也可以写出高级iOS自定义控件动画回顾全程CRNetworkButton 其实只用了三个武器CALayer 做属性动画、CAShapeLayer 画一切路径、状态机编排动画顺序。当你理解了这三者的组合拳无论是加载按钮、进度环、还是任何奇思妙想的 iOS 自定义控件动画都能信手拈来。建议你打开 CRNetworkButton.swift对照本文逐一注释每个动画的为什么再亲手改一改参数试试效果——动手永远是学习 iOS 动画最快的路。【免费下载链接】CRNetworkButtonSend Button for iOS项目地址: https://gitcode.com/gh_mirrors/cr/CRNetworkButton创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考