Swift中如何根据绘制的UIBezierPath获取frame给折线图添加渐变?
当然可以通过你存储的graphedInvestedPoints数组计算渐变层所需的frame,要实现折线下方填充渐变的效果,还需要配合路径遮罩完成,具体实现如下:
实现逻辑
- 遍历所有绘制点,拿到点集的边界值:最小X坐标、最大X坐标、最小Y坐标(iOS视图坐标系从上到下Y值递增,最小Y对应折线最高点)
- 基于边界值计算渐变层的frame,覆盖整个折线到填充底部的区域
- 生成闭合的贝塞尔路径:依次连接所有折线点,再连接到折线区域右下角、左下角,形成闭合的填充区域
- 用闭合路径生成遮罩层,给渐变层设置遮罩,让渐变只显示在折线下方区域
完整实现代码
func addGradient(){ let colorTop = UIColor(hexString: blueHexString) let colorBottom = UIColor.white // 1. 计算点集的边界值 let minX = graphedInvestedPoints.map{$0.x}.min() ?? 0 let maxX = graphedInvestedPoints.map{$0.x}.max() ?? self.bounds.width let minY = graphedInvestedPoints.map{$0.y}.min() ?? 0 // 填充底部的Y值,可替换为你折线X轴的Y坐标,没有的话用视图底部高度即可 let bottomY = self.bounds.height // 2. 设置渐变层frame let gradientLayer = CAGradientLayer() gradientLayer.colors = [colorTop.cgColor, colorBottom.cgColor] gradientLayer.locations = [0.0, 1.0] gradientLayer.frame = CGRect(x: minX, y: minY, width: maxX - minX, height: bottomY - minY) // 若你的折线占满整个视图宽度,也可以直接用gradientLayer.frame = self.bounds,适配性更强 // 3. 生成闭合填充路径做遮罩 let maskPath = UIBezierPath() guard !graphedInvestedPoints.isEmpty else { return } // 移动到第一个点 maskPath.move(to: graphedInvestedPoints[0]) // 连接所有折线点 for point in graphedInvestedPoints.dropFirst() { maskPath.addLine(to: point) } // 连接到底部两个点形成闭合区域 maskPath.addLine(to: CGPoint(x: maxX, y: bottomY)) maskPath.addLine(to: CGPoint(x: minX, y: bottomY)) maskPath.close() // 4. 设置遮罩 let maskLayer = CAShapeLayer() maskLayer.path = maskPath.cgPath gradientLayer.mask = maskLayer self.layer.insertSublayer(gradientLayer, at: 0) }
注意事项
如果你的视图会发生尺寸变化(比如横竖屏切换、父视图布局更新),需要在layoutSubviews方法中同步更新gradientLayer的frame和maskLayer的path,避免渐变错位。
内容的提问来源于stack exchange,提问作者aFella
相关产品推荐
相关产品推荐

