• 用CAShapeLayer实现一个简单的饼状图(PieView)


    自己写了一个简单的PieView,demo在这里:https://github.com/Phelthas/LXMPieView
    效果如图:
     
    实现方法:
    绘制饼状图所需的值只有各个扇形对应的值及对应的颜色,但可能会有很多附加的元素需要显示(比如字体颜色,字体大小等),
    所以将每个扇形所需的数据封装为一个model对象,方便以后扩展。
     
    1,绘制每个扇形,需要知道扇形的startAngle和endAngle,所以需要计算每个扇形所占的百分比及角度,
    然后第一个扇形的start是0,end是第一个扇形的角度,
    第二个扇形的start是第一个扇形的end,第二个扇形的end是前两个扇形的角度之和,以此类推
    这里写死了饼状图从-0.5*Pi的位置开始绘制,所以计算出每个扇形的startAngle和endAngle,分别保存到数组中。
     
    2,绘制各个扇形,
    用UIBezierPath的- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);方法
    注意这里这里要用 moveToPoint和 addLineToPoint方法绘制成闭合曲线,方便后面判断。
    依次add到self.layer上即可
     
    3,添加描述label
    这里是计算出每个label应该位于的中心位置,然后把label 直接add到view上。中心位置根据点在圆中的位置用几何方法(忘了的补初中数学)算出来。
     
    4,旋转动画
    这里还是用layer的mask属性来达到部分渲染的效果,参考我之前的解释:http://www.cnblogs.com/Phelthas/p/4643400.html
     
    5,添加点击事件
    这里只用了一个tapGesture添加到view上,然后通过gesture的location来判断点中的是哪个区域。
    那怎么判断location这个点在不在某个区域内呢???
    苹果提供了一个高大上的方法:
    /* Return true if `point' is contained in `path'; false otherwise. A point
       is contained in a path if it is inside the painted region when the path
       is filled; if `eoFill' is true, then the even-odd fill rule is used to
       evaluate the painted region of the path, otherwise, the winding-number
       fill rule is used. If `m' is non-NULL, then the point is transformed by
       `m' before determining whether the path contains it. */

    CG_EXTERN bool CGPathContainsPoint(CGPathRef __nullable path,
        const CGAffineTransform * __nullable m, CGPoint point, bool eoFill)
        CG_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);
     
    例:
        CGPoint location = [sender locationInView:sender.view];
        CGAffineTransform transform = CGAffineTransformIdentity;   
        NSInteger index = -1;
        for (int i = 0; i < self.subLayerArray.count; i ++) {
            CAShapeLayer *shapeLayer = self.subLayerArray[i];
            if (CGPathContainsPoint(shapeLayer.path, &transform, location, 0)) {
                index = i;
                break;
            }
        }
     
    6,用delegate的方式将点击事件回调出去
    这个只是为了方便外部调用而进行的封装,同时也是为了逻辑分离,代码整洁~~
  • 相关阅读:
    git commit --amend
    webpack代码分割
    selection And range js
    自动化测试
    python学习路线图
    Java--解决JDK14没有jre问题
    Java-win下环境变量设置
    Jenkins忘记admin密码拯救方法
    Windows或linux下 pip设置默认豆瓣镜像源
    ChromeDriver与Chrome版本对应参照表及ChromeDriver下载链接
  • 原文地址:https://www.cnblogs.com/Phelthas/p/4892854.html
Copyright © 2020-2023  润新知