尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AGCircularPicker源码解析②:渐变圆环渲染与像素级取色的隐藏技巧

AGCircularPicker源码解析②:渐变圆环渲染与像素级取色的隐藏技巧 AGCircularPicker源码解析②渐变圆环渲染与像素级取色的隐藏技巧【免费下载链接】AGCircularPickerAGCircularPicker is helpful component for creating a controller aimed to manage any calculated parameter项目地址: https://gitcode.com/gh_mirrors/ag/AGCircularPicker本文是 AGCircularPicker 源码解析的第二篇。AGCircularPicker 是一款面向 iOS 的轻量圆形选择器circular picker组件本篇拆解它的两大核心技术渐变圆环渲染与像素级取色——看它如何用一张带角度的渐变图裁出圆形又如何抠出手指所在位置的精确颜色新手也能看懂。一、渲染渐变圆环「渐变图 圆形遮罩」组合技 很多人渲染渐变圆盘的第一反应是直接用 CAGradientLayer。但 AGCircularPickerView 的做法是先把渐变画成一张 UIImage再用遮罩裁成圆形。这条渲染链的核心在AGCircularPicker/Classes/AGCircularPickerView.swift的setupView()L122-L166。第一步按指定角度绘制线性渐变图入口是给 UIImage 增加的类方法见AGCircularPicker/Classes/AGCircularPickerExtensions.swiftL175-L196let degree: CGFloat (angle 90) * .pi / 180 let center CGPoint(x: size.width / 2, y: size.height / 2) let startPoint CGPoint(x: center.x - cos(degree) * size.width / 2, y: center.y - sin(degree) * size.height / 2) let endPoint CGPoint(x: center.x cos(degree) * size.width / 2, y: center.y sin(degree) * size.height / 2) context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [])这里有两个小机关 90是角度偏移当gradientAngle传 0 时渐变恰好是从上到下符合直觉起止点由一个角度通过三角函数算出旋转渐变时中心点始终不变所以只改一个角度数字整条渐变就跟着转。方法的四个参数colors / locations / size / angle分别是渐变色数组、各色对应的位置0~1、绘制尺寸和旋转角度。第二步用图层遮罩把渐变裁成圆形draw(_:)L168-L184先用四段三次贝塞尔曲线拼出一个完整的圆L310-L344控制点距离是radius * 0.552——0.552 正是近似 1/4 圆弧的经典魔数按当前角度旋转后做了一件关键的事let shapeMask CAShapeLayer() shapeMask.path ellipsePath.cgPath super.layer.mask shapeMask把圆形路径设为super.layer的遮罩后渐变图、旋钮等所有子层会一起被圆形裁剪只露出圆内那一块渐变。这种遮罩写法比直接用 CAGradientLayer 更灵活——mask 可以换成任何路径环、弧线、异形都能做。第三步加上可拖动的白色旋钮knobPath(rect:)L304-L308在圆的顶部画一个直径 9pt 的小圆knobLayer填充纯白置顶。拖动时旋钮跟随手指绕圆转动就是选择器的指针。二、像素级取色用 1×1 上下文「抠出手指所在的颜色」整个项目最隐蔽的技巧是拖动旋钮时标题文字颜色会实时变成渐变在该处的颜色。项目没有手动插值计算渐变色而是直接对屏幕上的像素取色。如何从 CALayer 中读出单个像素实现是 CALayer 扩展的colorOfPoint(point:)见AGCircularPicker/Classes/AGCircularPickerExtensions.swiftL202-L224核心就这几行let pixel UnsafeMutablePointerCUnsignedChar.allocate(capacity: 4) let context CGContext(data: pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) context!.translateBy(x: -correctedPoint.x, y: -correctedPoint.y) render(in: context!)思路有点反直觉但很优雅创建一个1×1 的离屏上下文它的 4 字节内存正是一个像素的 RGBAtranslateBy平移坐标系让目标像素恰好落在上下文原点render(in:)把整棵图层树重新渲染进这个 1×1 上下文——被压进内存的就是目标像素的 RGBA读出pixel[0...3]除以 255即得到 UIColor。还有一个细节值得学习取色前先把点用min/max夹紧到边界内缩 2 点的位置拖到边缘也不会越界读取。两个关键调用点初始化与拖动时初始化完成后L159-L165算出旋钮位置调用gradientImageView.layer.colorOfPoint(point:)把初始颜色通过circularPickerViewDidEndSetupWith交给 delegate拖动过程中handleTouchesL203-L224先把触点钳制到圆环边缘内然后currentColor gradientImageView.layer.colorOfPoint(point: correctedPoint) delegate?.circularPickerViewDidChangeValue(currentValue.round(minValue), color: currentColor ?? .black, index: index)注意取色对象是gradientImageView.layer即渐变图层本身所以取到的颜色是纯渐变色不会被白色旋钮或标题干扰。这个技巧的好处是所见即所得无论渐变有几段色、位置怎么分布、角度多大取到的颜色都与用户肉眼看到的像素完全一致一行插值公式都不用写。代价是render(in:)会触发一次重绘因此它适合单点采样不适合批量扫图。三、自定义实战3 行代码换颜色、位置与角度 ⚙️上面渲染用的三个参数全部收敛在一个结构体里见AGCircularPicker/Classes/AGCircularPickerOption.swiftL105-L151参数作用默认值gradientColors渐变色数组青 (0,237,233) → 蓝 (0,135,217) → 紫 (138,28,195)gradientLocations每种颜色的位置0~1均匀分布gradientAngle渐变旋转角度度0只传颜色数组时位置会自动均分传角度渐变随之旋转。官方示例Example/AGCircularPicker/MultiPickerViewController.swift中hours 轮盘用gradientAngle: 20、minutes 用gradientAngle: -20相邻两个轮盘就形成了镜像渐变let hourColorOption AGCircularPickerColorOption( gradientColors: [hourColor1, hourColor2, hourColor3], gradientAngle: 20)UI 侧只需在 delegate 回调里用取到的颜色更新视图。示例Example/AGCircularPicker/SinglePickerViewController.swift的做法func circularPickerViewDidChangeValue(_ value: Int, color: UIColor, index: Int) { titleLabel.text String(format: %02d, value) titleLabel.textColor color }四、本篇总结技巧位置一句话要点按角度画线性渐变图AGCircularPickerExtensions.swiftL175-L196一个角度决定渐变方向圆形遮罩裁剪AGCircularPickerView.swiftL179-L181layer.mask赋任意路径即可裁出任意形状1×1 上下文取色AGCircularPickerExtensions.swiftL202-L224把图层重渲进单个像素得到真实颜色手指位置取色回调AGCircularPickerView.swiftL203-L224所见即所得免去手动插值下一篇会讲解AGCircularPickerExtensions.swift中的向量与角度数学扩展如何算出两点间的夹角并把角度 ↔ 数值的换算完整闭环。【免费下载链接】AGCircularPickerAGCircularPicker is helpful component for creating a controller aimed to manage any calculated parameter项目地址: https://gitcode.com/gh_mirrors/ag/AGCircularPicker创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表