授人以鱼不如授人以渔,学会实现方式才能更好的实现和维护
准备工作 原数据 是从大到小 是有序数组
需要先按照 如图分配顺序
每个模块里有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)
}
}
计算解释:
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)
}
}