美文网首页iOS学习资料绘画iOS学习
听说你想做个饼状图(iOS)

听说你想做个饼状图(iOS)

作者: 满庭花醉三千客 | 来源:发表于2017-01-19 16:41 被阅读563次

    最近项目需求,做了一个饼状图,整体效果还可以接受,故拿出来和大家分享一下,并希望能得到大神的一些改进建议或者意见~~

    先上效果图:

    all.gif

    下面简单梳理一下整体的流程:

    第一步:新建一个继承于UIView的文件。

    此时我们需要这几样东西:

    (1)数据源(区分比率)。

    (2)颜色源(视觉信息)。

    (3)标题源(文本信息)。

    第二步:拿到数据源之后开始处理数据,算出各个数据的占比。

    第三步:选定圆心,使用BezierPath来画圆并填充颜色。

    需要注意的事:

    (1)开始的弧度为-π/2,也就是从圆的顶部开始。

    (2)第n个圆弧开始的弧度为第n-1个圆弧结束的弧度

    (3)圆弧的弧度取自数据源对应项的比率*2π

    此时我们能得到这样的效果:

    饼状图

    第四步:我们要做一些友好的展示效果——动画

    动画是通过maskLayer的strokeEnd做改变来实现动画效果的。

    核心的一张图:

    maskLayer的构造

    maskLayer的path是这样构造的,实际是红色的弧线,但是lineWidth(宽度)为圆饼的半径,这样我们就可以覆盖整个饼状图了,并可以通过控制strokeEnd来动画展示饼状图了。

    第五步:点击效果

    有了动画之后的饼状图用户感觉会好很多了,如果再加上交互,用户可以点击的话,那样就更棒了。

    点击之后的处理是最关键的,贴上代码:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        //不能点击则不做处理了
        if (!self.canClick) {
            return;
        }
        
        CGPoint touchPoint = [[touches anyObject] locationInView:self];
        for (CustomShapeLayer *shapeLayer in pieShapeLayerArray) {
            
            //如果只有一个模块,那么动画就要变化了,不是简单的偏移了
            if (self.segmentDataArray.count == 1) {
                shapeLayer.isOneSection = YES;
            }
    
            
            //判断选择区域
            shapeLayer.clickOffset =  [self preferGetUserSetValue:self.clickOffsetSpace withDefaultValue:15];
    
            if (CGPathContainsPoint(shapeLayer.path, 0, touchPoint, YES)) {
                
                //修改选中状态
                if (shapeLayer.isSelected) {
                    
                    shapeLayer.isSelected = NO;
                }else{
                    shapeLayer.isSelected = YES;
                    
                }
                
                NSInteger index = [pieShapeLayerArray indexOfObject:shapeLayer];
                
                //执行block并开始右侧小圆点动画
                [self dealClickCircleWithIndex:index];
                
    
            } else {
                
                shapeLayer.isSelected = NO;
            }
        }
    }
    

    点击时,我们根据isSelected做不同的处理,YES时,表示被选中,然后该模块的饼状图移动出来,移动的动画使用CABasicAnimation对path做处理;NO时,表示恢复原位,将该模块的饼状图复原。需要注意的是当你点击A块时,A被移动出来,此时点击B块,则B块移动出来的同时,A也要恢复回去。

    关键处理的代码:

      if (isSelected) {
            //center 往外围移动一点 使用cosf跟sinf函数
            newCenterPoint = CGPointMake(_centerPoint.x + cosf((_startAngle + _endAngle) / 2) * offset, _centerPoint.y + sinf((_startAngle + _endAngle) / 2) * offset);
        }
        //创建一个path
        UIBezierPath *path = [UIBezierPath bezierPath];
        //起始中心点改一下
        [path moveToPoint:newCenterPoint];
        [path addArcWithCenter:newCenterPoint radius:_radius startAngle:_startAngle endAngle:_endAngle clockwise:YES];
        [path addArcWithCenter:newCenterPoint radius:_innerRadius startAngle:_endAngle endAngle:_startAngle clockwise:NO];
        [path closePath];
        self.path = path.CGPath;
        
        //添加动画
        CABasicAnimation *animation = [CABasicAnimation animation];
        //keyPath内容是对象的哪个属性需要动画
        animation.keyPath = @"path";
        //所改变属性的结束时的值
        animation.toValue = path;
        //动画时长
        animation.duration = 0.35;
        //添加动画
        [self addAnimation:animation forKey:nil];
    

    至此流程的简单梳理已经完毕了,难度并不大,就是比较费心思而已。

    如有疏漏不足,还请大神们多多指教~

    共同进步,么么哒~

    最后附上完整的代码地址:
    完整代码

    相关文章

      网友评论

      • Samson_Xu:目前看到的使用最方便的轮子,感谢分享
        满庭花醉三千客:非常感谢您的肯定,大家一起进步哈~:blush:
      • luzsyn:楼主,请教一个需求,数据百分比显示在分区块儿内部,分区块儿的描述显示在对应的外部,并用一条颜色一致的线指示着,求帮助,谢谢
        luzsyn:@满庭花醉三千客 这是设计图,求帮忙想想,http://chuantu.biz/t6/18/1503477427x2088736387.png
        满庭花醉三千客:还有就是,当点击时,扇形向外移动,此时连线怎么办?一起移动吗?
        满庭花醉三千客:饼状图在中部,文字分别位于两侧,然后通过横线连接对应的色块吗?方便把你的需求再详细描述一下吗?
      • 浩青:怎么样修改文字到左侧呢?
        满庭花醉三千客:@幽默魔_f36e 将文本尽可能的左移,同时将图向右移动。还不能满足的话,再试一下调整字号。你需要什么样的效果,能说一下吗?
        626625266a26:文字稍长一点会被图挡住
        满庭花醉三千客:git 上面已经更新用法了。两个属性即可。:smile:
      • 小灬博:麻烦楼主了
      • 小灬博:刚开始的时候能不能就让他处于点击的状态,我需要这样的 效果
        满庭花醉三千客:已经处理好了,还是支持动画,你下载项目之后,可以查看到对应的设置。在ViewController.m文件的第136行,你可以设置selectedIndex为你需要的模块项即可。如果还有其他的需求,请留言给我哈
        满庭花醉三千客:那动画效果怎么处理?不要动画了吗?
      • LANXF:不错哦
        小灬博:@满庭花醉三千客 刚开始的时候 能不能让他处于点击状态
        满庭花醉三千客:谢谢支持~共同进步哈~:blush:

      本文标题:听说你想做个饼状图(iOS)

      本文链接:https://www.haomeiwen.com/subject/avpibttx.html