IOS-仿芝麻信用解读&王者荣耀雷达图实现

Posted 独立开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IOS-仿芝麻信用解读&王者荣耀雷达图实现相关的知识,希望对你有一定的参考价值。

目标

为了实现类似支付宝芝麻信用分解读的雷达图或王者荣耀的对战资料解读,如下图:

本文源码地址:IOSRadarView
版权声明:本文为博主原创文章,未经博主允许不得转载。来自:http://blog.csdn.net/qxs965266509
http://blog.csdn.net/qxs965266509/article/details/79601838

效果图

先给大家看一下我实现的小效果图,当然和芝麻信用还是不是完全一样的。

只展示了4种形状的图形,需要看其他效果可下载代码直接运行查看。

实现思路分析

  • 封装一个Model,即RadarModel,包含标题和百分比(title: String,percent: CGFloat)
  • 创建一个自定义View,即RadarView
  • 把RadarModel列表传递到RadarView中
  • 先绘制网状结构几边型,Radar计算每个环之间的间距和半径
  • 计算每个顶点的坐标,把顶点添加到CGMutablePath中
  • 然后把CGMutablePath赋值给CAShapeLayer的path,接着把CAShapeLayer添加到View的layer中即可
  • 接着绘制蓝色区域部分,同样,计算出蓝色区域的顶点坐标,把坐标添加到Path中,path赋值给CAShapeLayer的path,接着把CAShapeLayer添加到View的layer中即可
  • 蓝色区域的顶点坐标计算出后,绘制蓝色圆点
  • 最后绘制标题,根据每个形状最外层顶点的坐标,计算出标题的绘制坐标

代码实现

网状结构的绘制
//绘制的路径
let path = CGMutablePath()
        //网状半径之间的间距
        let radiuSpace: CGFloat = radius / CGFloat((side - 1))
        //角度
        let angle: CGFloat = CGFloat(Double.pi * 2 / Double(side))
        //视图的中心点
        let centerPoint = CGPoint(x: centerX, y: centerY)

        for ring in 0..<side 
            //当前环的半径
            let currentRadius: CGFloat = CGFloat(ring) * radiuSpace
            //存储当前环中的顶点坐标
            var array = [CGPoint]()
            for node in 0..<side 
                //顶点X坐标
                let x: CGFloat = currentRadius * CGFloat(sin(angle / 2 + angle * CGFloat(node))) + centerX
                //顶点Y坐标
                let y: CGFloat = currentRadius * CGFloat(cos(angle / 2 + angle * CGFloat(node))) + centerY
                //当前顶点的坐标
                let currentPoint = CGPoint(x: x, y: y)
                //添加当前顶点到环中
                array.append(currentPoint)
                //添加当前顶点到中心店之间线
                path.addLines(between: [currentPoint, centerPoint])
            
            //把最开始的顶点添加到尾部,形成闭环
            array.append(array[0])
            //根据顶点坐标的列表绘制线,一层层环就是这么形成的
            path.addLines(between: array)
        

side:边的数量,等于传递的Model列表长度
centerX,centerY:View的中心坐标

//创建Layer
var shapeLayer = CAShapeLayer()
//填充颜色设置为透明无色
shapeLayer.fillColor = UIColor.clear.cgColor
//背景颜色设置为透明无色
shapeLayer.backgroundColor = UIColor.clear.cgColor
//把上面创建的Path复制给ShapeLayer
shapeLayer.path = path
//绘制的线宽(粗细)
shapeLayer.lineWidth = lineWidth
//绘制线的颜色
shapeLayer.strokeColor = lineColor.cgColor
//当前Layer的位置和大小
shapeLayer.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
//添加当前layer到其他的layer中,到此就显示出网状结构了
layer.insertSublayer(shapeLayer, at: 0)

layer:自定义View的layer
frame:自定义View的frame

绘制浅蓝色区域
//定义蓝色区域的Path
let percentPath = CGMutablePath()
//添加顶点的列表
var array = [CGPoint]()
//遍历边长
for node in 0..<side 
    //蓝色区域顶点X
    let x: CGFloat = radius * sin(angle / 2 + angle * CGFloat(node)) * data[node].percent + centerX
    //蓝色区域顶点Y
    let y: CGFloat = radius * cos(angle / 2 + angle * CGFloat(node)) * data[node].percent + centerY
    //添加当前的顶点到列表中
    array.append(CGPoint(x: x, y: y))

//添加顶点列表到Path中
percentPath.addLines(between: array)
//同上绘制网状结构的设置一致
var reginLayer = CAShapeLayer()
reginLayer.fillColor = drawAreaColor.cgColor
reginLayer.backgroundColor = UIColor.clear.cgColor
reginLayer.path = percentPath
reginLayer.lineWidth = lineWidth
reginLayer.strokeColor = dotColor.cgColor
reginLayer.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)

layer.insertSublayer(reginLayer, above: shapeLayer)       
绘制蓝色区域顶点圆点
// array就是上面绘制蓝色区域的顶点
for item in array 
    //创建顶点的Layer
    let dotLayer = CATextLayer()
    //设置圆点的圆角
    dotLayer.cornerRadius = dotRadius
    //设置圆点的位置和大小
    dotLayer.frame = CGRect(x: item.x - dotRadius, y: item.y - dotRadius, width: dotRadius * 2, height: dotRadius * 2)
    //设置圆点的背景颜色
    dotLayer.backgroundColor = dotColor.cgColor
    //添加当前圆点的layer到dotsShapeLayer,dotsShapeLayer是一个ShapeLayer存放所有顶点圆点
    dotsShapeLayer.addSublayer(dotLayer)
绘制标题
for node in 0..<side 
            //获取当前标题的尺寸
            let size = getViewHeight(content: data[node].title)
            //计算出的标题X坐标
            var x: CGFloat = (radius + size.height * 0) * sin(angle / 2 + angle * CGFloat(node)) + centerX
            //计算出的标题Y坐标
            var y: CGFloat = (radius + size.height * 0) * cos(angle / 2 + angle * CGFloat(node)) + centerY
            //创建文本Layer
            let textLayer = CATextLayer()
            //设置字体大小
            textLayer.fontSize = 14
            //设置缩放
            textLayer.contentsScale = UIScreen.main.scale
            //设置对齐方式
            textLayer.alignmentMode = kCAAlignmentCenter
            //设置文本前景颜色
            textLayer.foregroundColor = titleTextColor
            //设置文本背景颜色
            textLayer.backgroundColor = UIColor.clear.cgColor
            //设置标题
            textLayer.string = data[node].title //"\\(node)\\(data[node].title)"

            //优化字体与网状结构之间的距离和位置调整,详细请看代码,可根据个人情况再次调整
            if x >= nightNodeArray[4].x && x <= nightNodeArray[3].x && y < frame.size.height / 2 
                x = x - size.width / 2
                y = y - size.height - space
             else if x > nightNodeArray[5].x && x < nightNodeArray[4].x &&
                y > nightNodeArray[4].y && y < nightNodeArray[5].y 
                x = x - size.width / 3 * 2
                y = y - size.height - space
             else if y >= nightNodeArray[5].y && y <= nightNodeArray[6].y && x < frame.size.width / 2 
                if y > frame.size.height / 2 
                    x = x - size.width - space
                    y = y - size.height / 3
                 else 
                    x = x - size.width - space
                    y = y - size.height / 3 * 2
                
             else if x > nightNodeArray[6].x && x < nightNodeArray[7].x &&
                y > nightNodeArray[6].y && y < nightNodeArray[7].y 
                x = x - size.width / 2
                y = y + space
             else if x >= nightNodeArray[7].x && x <= nightNodeArray[0].x && y > frame.size.height / 2 
                x = x - size.width / 2
                y = y + space
             else if x > nightNodeArray[0].x && x < nightNodeArray[1].x &&
                y > nightNodeArray[1].y && y < nightNodeArray[0].y 
                x = x - size.width / 5 * 2
                y = y + space
             else if y >= nightNodeArray[2].y && y <= nightNodeArray[1].y && x > frame.size.width / 2 
                x = x + space
                y = y - size.width / 3
             else if x > nightNodeArray[3].x && x < nightNodeArray[2].x &&
                y > nightNodeArray[3].y && y < nightNodeArray[2].y 
                x = x + space
                y = y - size.height
            

            textLayer.frame = CGRect(x: x, y: y, width: size.width, height: size.height)
            textShapeLayer.addSublayer(textLayer)
        

到此,基本的代码讲解就完了,有疑问可加微信,下图:
第一个是我的微信,觉得对你帮助较大的可扫描第二个图进行打赏,谢谢你的支持。

本文源码地址:IOSRadarView
版权声明:本文为博主原创文章,未经博主允许不得转载。来自:http://blog.csdn.net/qxs965266509
http://blog.csdn.net/qxs965266509/article/details/79601838

以上是关于IOS-仿芝麻信用解读&王者荣耀雷达图实现的主要内容,如果未能解决你的问题,请参考以下文章

浅谈canvas绘画王者荣耀--雷达图

Android自定义view之仿支付宝芝麻信用仪表盘

canvas仿芝麻信用分仪表盘

CSS3 流动边框(仿王者荣耀等待效果)的三种实现方式

CSS3 流动边框(仿王者荣耀等待效果)的三种实现方式

用canvas写仿支付宝中的芝麻信用分的效果