为了账号安全,请及时绑定邮箱和手机立即绑定

Swift 实现数据分布图 块状分布图

标签:
iOS Swift

授人以鱼不如授人以渔,学会实现方式才能更好的实现和维护

https://img1.sycdn.imooc.com//5dc523ef000165ac06460488.jpg

准备工作   原数据 是从大到小  是有序数组

需要先按照 如图分配顺序

https://img1.sycdn.imooc.com//5dc5257100014e8209700526.jpg

每个模块里有1到3个数据  再多就可以放到下个模块里了


1.处理数据 成模块分配模式 按上图分配 ->[[数据1,数据2],[数据3],[数据4,数据5],[数据6,数据7,数据8],[数据9,数据10],[数据11],[数据12,数据13]......]   


  //处理数组

    func makeDownDatas(arr:[CGFloat]) -> [[CGFloat]] {

        var dataList:[[CGFloat]] = []

        var left:CGFloat = 0

        var num = 0

        while num < (arr.count <= 10 ? arr.count : 10) {

            let item = arr[num]

            if item/(1.0-left) > 0.4 {

                dataList.append([item])

                left = left + item

                num += 1

            }else if dataList.count == 9 {

                var lastSum:CGFloat = 0

                for index in 9..<arr.count{

                    lastSum = lastSum + arr[index]

                }

                dataList.append([lastSum])

                left = left + lastSum

                num += 1

            }else if num < arr.count-2{

                let second = arr[num+1]

                if (item+second)/(1.0-left) > 0.45{

                    dataList.append([item,second])

                    num += 2

                    left = left + item + second

                }else if num < arr.count-3{

                    let third = arr[num+2]

                    dataList.append([item,second,third])

                    num += 3

                    left = left + item + second + third

                }

            }

        }

        return dataList

    }

准备数组元素求和

//求和

    func sumDatas(arr:[CGFloat]) -> CGFloat {

        guard arr.count > 0 else {

            return 0

        }

        var sum:CGFloat = 0

        for item in arr {

            sum += item

        }

        return sum

    }

2.UI绘制 难点,计算每个不同颜色的子块的大小和位置

func reloadDatas(datas:[CGFloat]){

        var left:CGFloat = 0

        var hasSum:CGFloat = 0

        var top:CGFloat = 0

        let width = self.frame.width

        let height = self.frame.height

        var sumIndex = 0

        let newArr =  makeDownDatas(arr: datas)

        for (index,array) in newArr.enumerated() {

            let sum = sumDatas(arr: array)

            

            let w = index%2 == 0 ? (width - left)*sum/(1.0-hasSum) : (width-left)

            let h = index%2 == 0 ?                    (height-top) : (height-top)*sum/(1.0-hasSum)

            var subTop = top

            var subLeft = left

            for (_,item) in array.enumerated(){

                let subW = index%2 == 0 ? w : w * item/sum

                let subH = index%2 == 0 ? h*item/sum : h

                

                let sep = UIView(frame: CGRect(x: subLeft, y: subTop, width: subW, height: subH))

                sep.backgroundColor = colors[sumIndex]

                self.addSubview(sep)

                

                let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapViewForReloadDatas(tap:)))

                sep.addGestureRecognizer(tap)

                

                let lab = UILabel(frame: CGRect(x: 5, y: 5, width: (subW-10 < 20 ? subW : subW-10), height: (subH < 10 ? 0 : 10)))

                lab.textColor = UIColor.white

                lab.text = "\(item)"

                lab.font = UIFont.systemFont(ofSize: 10)

                sep.addSubview(lab)

                

                subLeft = subLeft + (index%2 == 0 ? 0 : w*item/sum)

                subTop = subTop + (index%2 == 0 ? h*item/sum : 0)

                sumIndex += 1

            }

            hasSum += sum

            left = left + (index%2 == 0 ? w : 0)

            top = top + (index%2 == 0 ? 0 : h)

        }

    }

计算解释:

https://img1.sycdn.imooc.com//5dc528520001b7ae15441174.jpg

index%2 == 0 为蓝色模块的计算下标符合的条件

index%2 == 1 为绿色模块的计算下标符合的条件

其中w为当下index下标的模块的宽度,h为高度

left 为当前计算模块的左边距,right为当前计算模块的上边距

hasSum 为已经计算过的数据的和

sumIndex 为子数据的计算下标,注意和模块的下标index的区别  (每个模块里可能有1-3个子数据)

子模块的位置大小的计算

subTop、subLeft 为子数据相对于所在模块的上边距和左边距

subW、subH为子数据的宽和高

其中的Tap手势为点击刷新所在模块的数据的展开,已实现,但是有待优化,动画过渡有点生硬

其中子数据的展示,写在了展开方法里


 @objc func tapViewForReloadDatas(tap:UITapGestureRecognizer) -> Void {

         UIView.animate(withDuration: 0.7) {

            for item in self.subviews{

                item.alpha = 0

            }

        }

        let subDatas = [CGFloat(0.28),CGFloat(0.2),CGFloat(0.18),CGFloat(0.16),CGFloat(0.10),CGFloat(0.06),CGFloat(0.02)]

        let rect = tap.view?.frame

         let hotMap = HotMapView(frame:self.bounds)

        hotMap.reloadDatas(datas: subDatas)

        self.addSubview(hotMap)


        hotMap.transform = CGAffineTransform.init(scaleX: rect!.width/self.frame.width, y: rect!.height/self.frame.height)

        hotMap.center = tap.view!.center

        UIView.animate(withDuration: 0.5) {

             hotMap.transform = CGAffineTransform.identity

            hotMap.center = CGPoint(x: self.frame.width*0.5, y: self.frame.height*0.5)

        }

    }

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
32
获赞与收藏
322

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消