iOS学习资料绘画iOS学习

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

2017-01-19  本文已影响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];

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

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

共同进步,么么哒~

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

上一篇下一篇

猜你喜欢

热点阅读