iOS绘制3D饼图的实现方法

发布时间 - 2026-01-10 22:19:26    点击率:

实现核心

     1.压缩饼图,使饼图有3D的效果,并不是真正的画了个3D圆柱

     2.绘制厚度,带阴影效果,让看上去像是圆柱的高

     3.路径添加好了,用颜色填充后绘制一下,添加阴影后还需绘制一遍

饼图添加阴影的思考

之前这加阴影的一段不是很明白,为啥设颜色和阴影都要draw一次

进过反复的测试,我自己分析了一下,每次draw一下想当于,把当前的设置画出来,再次draw就在这基础上,再画最近的设置,这里加颜色和阴影就像是一层一层的画上去。要是不draw的话,再设置颜色相当于重新设置了颜色,之前设置的颜色就无效了。同时要结合path使用,如果设置一场颜色draw一次,再设置颜色draw一次,后面设置的颜色是无用的。需要添加阴影的部分,需要用path路径绘制。

效果图

3D饼图的核心代码如下:

#import "SSSolidCakeView.h"

@implementation SSSolidCakeView
#pragma mark 重写绘制方法
- (void)drawRect:(CGRect)rect
{
  //第一步获得上下文
  CGContextRef cakeContextRef = UIGraphicsGetCurrentContext();
  //反锯齿,让图形边缘更加柔和(Sets whether or not to allow anti-aliasing for a graphics context.)
  CGContextSetAllowsAntialiasing(cakeContextRef, TRUE);
  //缩放坐标系的比例,通过设置y轴压缩,然后画代阴影的厚度,就画出了像是3D饼图的效果
  CGContextScaleCTM(cakeContextRef, _xScale, _yScale);
  //饼图最先的起始角度
  CGFloat startAngle =0;

  for (int i = 0; i<_dataArray.count; i++) {
    //画饼的横截面,上一部分完整的圆
    //cake当前的角度
    CGFloat currentAngle = [_dataArray[i] floatValue];
    //结束的角度
    CGFloat endAngle = startAngle + currentAngle;
    //每一块cake的起点,也就是圆心
    CGContextMoveToPoint(cakeContextRef, _cakeCenter.x, _cakeCenter.y);

    //添加对应角度扇形
    CGContextAddArc(cakeContextRef, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*M_PI*2, endAngle*M_PI*2, 0);

    //得到对应的颜色
    UIColor *currentColor = _colorArray[i];
    //设置边界颜色
    CGContextSetStrokeColorWithColor(cakeContextRef, currentColor.CGColor);
    //设置填充颜色
    CGContextSetFillColorWithColor(cakeContextRef, currentColor.CGColor);
    //画子路径,这里就绘制还不是在画完厚度再绘制,是因为并不需要绘制所有cake的厚度,但是上一部分的圆是都要绘制的
    CGContextDrawPath(cakeContextRef, kCGPathFill);
    //饼图上一部分圆,startAngle处的起点坐标
    CGFloat upStartX = _cakeCenter.x+_cakeRadius*cos(startAngle*2*M_PI);
    CGFloat upStartY = _cakeCenter.y+_cakeRadius*sin(startAngle*2*M_PI);
    //饼图上一部分圆,endAngle处的终点坐标
    CGFloat upEndX = _cakeCenter.x+_cakeRadius*cos(endAngle*2*M_PI);
    CGFloat upEndY = _cakeCenter.y+_cakeRadius*sin(endAngle*2*M_PI);

    //饼图厚度在角度结束处y坐标
    CGFloat downEndY = upEndY + _cakeHeight;
    //画圆柱的侧面,饼图的厚度,圆柱的前半部分能看到,后半部分是看不到
    //开始的角度如果>=M_PI,就会在圆柱的后面,侧面厚度就没必要画了
    if (startAngle<0.5) {
      //绘制厚度
      CGMutablePathRef path = CGPathCreateMutable();
      CGPathMoveToPoint(path, nil, upStartX, upStartY);
      //当结束的角度>0.5*2*M_PI时,结束的角度该是M_PI的地方(视觉原因)
      if (endAngle>0.5) {
        //上部分的弧
        CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*2*M_PI, M_PI, 0);
        //在角度结束的地方,上部分到下部分的直线
        CGPathAddLineToPoint(path, nil, _cakeCenter.x-_cakeRadius, _cakeCenter.y+_cakeHeight);
        //下部分的弧
        CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y + _cakeHeight, _cakeRadius, M_PI, startAngle*2*M_PI, 1);
        //在角度开始的地方,从下部分到上部分的直线
        CGPathAddLineToPoint(path, nil, upStartX, upStartY);

      }
      else{
        //上部分的弧
        CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y, _cakeRadius, startAngle*2*M_PI, endAngle*2*M_PI, 0);
        //在角度结束的地方,上部分到下部分的直线
        CGPathAddLineToPoint(path, nil, upEndX, downEndY);
        //下部分的弧
        CGPathAddArc(path, nil, _cakeCenter.x, _cakeCenter.y + _cakeHeight, _cakeRadius, endAngle*2*M_PI, startAngle*2*M_PI, 1);
        //在角度开始的地方,从下部分到上部分的直线
        CGPathAddLineToPoint(path, nil, upStartX, upStartY);

      }
      //之前这一段不是很明白,为啥设颜色和阴影都要draw一次
      //我自己尝试并理解分析了一下,每次draw一下想当于,把当前的设置画出来,再次draw就在这基础上,再画当前的设置,这里加颜色和阴影就是一层一层的画上去。要是不draw的话,再设置颜色相当于重新设置了颜色,之前设置的颜色就无效了。
      CGContextAddPath(cakeContextRef, path);
      CGContextDrawPath(cakeContextRef, kCGPathFill);
      //加阴影
      [[UIColor colorWithWhite:0.2 alpha:0.4] setFill];
      CGContextAddPath(cakeContextRef, path);
      CGContextDrawPath(cakeContextRef, kCGPathFill);

    }

    //最后一句,上一块的结束角度是下一块的开始角度
    startAngle = endAngle;

  }
  //此时不能用以下的方法填充,会导致饼图就一种颜色
  //CGContextFillPath(contextRef);
}
-(void)setDataArray:(NSArray *)dataArray
{
  _dataArray = dataArray;
  //重新绘制
  [self setNeedsDisplay];
}

这里要说明一下,我的数组是百分比数组,由数值转化为百分比的过程我没有在这里处理。

如何使用view:

  self.solidCakeView = [[SSSolidCakeView alloc]init];
  self.solidCakeView.dataArray = _dataArray;
  self.solidCakeView.colorArray = _colorArray;
  self.solidCakeView.nameArray = _nameArray;
  self.solidCakeView.cakeCenter = CGPointMake(200, 200);
  self.solidCakeView.cakeRadius = 100;
  self.solidCakeView.cakeHeight = 30;
  self.solidCakeView.xScale = 1;
  self.solidCakeView.yScale = 0.8;
  self.solidCakeView.backgroundColor = [UIColor whiteColor];
  self.solidCakeView.frame = CGRectMake(0, 0, PhoneScreen_WIDTH-100, PhoneScreen_HEIGHT-20);
  [self.view addSubview:self.solidCakeView];

3D饼图如何绘制及使用已经用代码介绍完了,相信看到这大家应该也能实现3D饼图了。

本文参考了:http://blog.csdn.net/donny_zhang/article/details/9145379  感谢博主!

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位iOS开发者们能有一定的帮助,如果有疑问大家可以留言交流。


# ios  # 绘制饼图  # 绘制饼状图  # 饼状图  # demo  # iOS 生成图片验证码绘制实例代码  # iOS使用Charts框架绘制饼状图  # iOS使用Charts框架绘制折线图  # IOS绘制虚线的方法总结  # iOS App开发中用CGContextRef绘制基本图形的基本示例  # IOS绘制动画颜色渐变折线条  # IOS 绘制三角形的实例详解  # 都要  # 画出  # 基础上  # 不是很  # 上一  # 画了  # 画上  # 图上  # 是在  # 在这里  # 是因为  # 好了  # 一句  # 还不  # 也能  # 就在这  # 会在  # 有一定  # 一遍  # 就没 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 详解Android中Activity的四大启动模式实验简述  如何在VPS电脑上快速搭建网站?  轻松掌握MySQL函数中的last_insert_id()  Laravel Session怎么存储_Laravel Session驱动配置详解  JavaScript如何实现类型判断_typeof和instanceof有什么区别  Python图片处理进阶教程_Pillow滤镜与图像增强  如何基于云服务器快速搭建个人网站?  音响网站制作视频教程,隆霸音响官方网站?  JS碰撞运动实现方法详解  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  青岛网站建设如何选择本地服务器?  Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)  Laravel如何创建自定义Artisan命令?(代码示例)  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  Laravel如何发送系统通知?(Notification渠道示例)  jquery插件bootstrapValidator表单验证详解  如何为不同团队 ID 动态生成多个非值班状态按钮  Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  Laravel Fortify是什么,和Jetstream有什么关系  Android自定义控件实现温度旋转按钮效果  手机网站制作与建设方案,手机网站如何建设?  Laravel如何使用withoutEvents方法临时禁用模型事件  HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】  如何用wdcp快速搭建高效网站?  香港服务器选型指南:免备案配置与高效建站方案解析  Laravel中间件如何使用_Laravel自定义中间件实现权限控制  如何快速搭建高效可靠的建站解决方案?  简单实现Android文件上传  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  活动邀请函制作网站有哪些,活动邀请函文案?  在线制作视频网站免费,都有哪些好的动漫网站?  Laravel如何使用Livewire构建动态组件?(入门代码)  重庆市网站制作公司,重庆招聘网站哪个好?  如何在服务器上配置二级域名建站?  Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层  简历没回改:利用AI润色让你的文字更专业  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  详解阿里云nginx服务器多站点的配置  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  如何破解联通资金短缺导致的基站建设难题?  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  海南网站制作公司有哪些,海口网是哪家的?  Laravel如何处理和验证JSON类型的数据库字段