iOS — 简单的任务绘制复盘
- 2020 年 3 月 16 日
- 筆記
//: A UIKit based Playground for presenting user interface import UIKit import PlaygroundSupport class MyView :UIView{ let bgColor = UIColor.lightGray let forColor = UIColor.orange let progress = 0.93 let total = 150 let startOffsetY = CGFloat(40) let rectHeight = CGFloat(20) var hoverX = CGFloat(0) var indicators:[String] = ["0","20","40","60","80","100","120","……"] override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() context?.setStrokeColor(forColor.cgColor) // context?.setLineWidth(3) context?.move(to: CGPoint(x: 10, y: startOffsetY)) context?.addLine(to: CGPoint(x: self.frame.width-20, y: startOffsetY)) context?.addLine(to: CGPoint(x: self.frame.width-20, y: startOffsetY + rectHeight)) context?.addLine(to: CGPoint(x: 10, y: startOffsetY+rectHeight)) context?.addLine(to: CGPoint(x: 10, y: startOffsetY)) hoverX = (self.frame.width-20)*CGFloat(progress) context?.move(to: CGPoint(x: hoverX, y: startOffsetY)) context?.addLine(to: CGPoint(x: (self.frame.width-20)*CGFloat(progress), y:startOffsetY-10)) context?.strokePath() let ctx1 = UIGraphicsGetCurrentContext() ctx1?.setFillColor(bgColor.cgColor) ctx1?.fill(CGRect(x: 10, y: startOffsetY, width: (self.frame.width-20)-6, height: rectHeight)) let ctx2 = UIGraphicsGetCurrentContext() ctx2?.setFillColor(forColor.cgColor) ctx2?.fill(CGRect(x: 10, y: startOffsetY, width: (self.frame.width-20)*CGFloat(progress)-3*2, height: rectHeight)) let items = indicators var index = 0 let step = self.frame.width / CGFloat(items.count) items.forEach { (txt) in let titleWidth = (txt as NSString).size(withAttributes: nil).width (txt as NSString).draw(at: CGPoint(x: 10 + CGFloat(step * CGFloat(index))-titleWidth/2, y: startOffsetY+rectHeight), withAttributes: nil) index = index+1 } let title = "您已完成( Int(Double(total) * progress) )场比赛" let titleWidth = (title as NSString).size(withAttributes: nil).width let titleHeight = (title as NSString).size(withAttributes: nil).height var titleX = hoverX - titleWidth/2 if titleX<0 { titleX = 0 } if hoverX + titleWidth/2 > self.frame.width { titleX = self.frame.width-titleWidth } // if titleX + titleWidth >= self.frame.width { // titleX = self.frame.width-10-titleWidth // } (title as NSString).draw(at: CGPoint(x:titleX , y: startOffsetY-10-titleHeight), withAttributes: [NSAttributedString.Key.foregroundColor:forColor]) } } class MyViewController : UIViewController { override func loadView() { let view = MyView() view.backgroundColor = .white let label = UILabel() label.frame = CGRect(x: 150, y: 200, width: 200, height: 20) label.text = "Hello World!" label.textColor = .black view.addSubview(label) self.view = view } } // Present the view controller in the Live View window PlaygroundPage.current.liveView = MyViewController()

iOS图形绘制以及文本绘制一直是lz避免触及的地方,不为别的就是感觉这个东西不够对象化,比较零散。但因这次项目中遇到了这么个表达进度而又不是找不到现实UI库的情况下只能硬着头皮上拉,现在复盘一下当时的心理路程:
1 我需要知道怎么划线
2 我需要怎么知道设置颜色
3 我需要画个按比例动态变更的矩形
4 我需要为矩形填充背景色
于是按照这些就去搜寻怎么画下,怎么给线条设置颜色,怎么设置线条的起点啊,怎么使用线条连接成一个矩形,怎么设置颜色啊……
下面我们拆分一下:
1 设置画笔起点 划线 和 设置线条颜色
//拿到图像上下文,也就是个句柄,相当于面向对象的中实例的引用 let context = UIGraphicsGetCurrentContext() //设置一个颜色,当划线时就是使用这个颜色 context?.setStrokeColor(forColor.cgColor) //为画笔在屏幕上选择一个起点 context?.move(to: CGPoint(x: 10, y: startOffsetY)) //添加线条,从一个点画向另一个点,形成线条 context?.addLine(to: CGPoint(x: self.frame.width-20, y: startOffsetY)) //告诉上下文完成路径的添加, context?.strokePath()
2 化矩形
有了1的基础我们就查找了一下怎么绘制矩形,以及上文中我们看到矩形显示,其实是两个矩形叠加的想过(相互遮挡形成),当然了也可采用相邻的两个矩形(lz其实偷懒了)
let ctx1 = UIGraphicsGetCurrentContext() //矩形填充色 ctx1?.setFillColor(bgColor.cgColor) // 根据设置好的填充色,在特定的框中涂抹成矩形 ctx1?.fill(CGRect(x: 10, y: startOffsetY, width: (self.frame.width-20)-6, height: rectHeight)) let ctx2 = UIGraphicsGetCurrentContext() ctx2?.setFillColor(forColor.cgColor) ctx2?.fill(CGRect(x: 10, y: startOffsetY, width: (self.frame.width-20)*CGFloat(progress)-3*2, height: rectHeight))
3 进度文本的显示
我们看一下表象形式:按照比例将数字均匀的成直线排开。那么我们需要知道哪些:
1 文本的绘制位置
2 文本绘制时的长度
3文本在绘制时是否会超出边界导致看不到的情况发生
items.forEach { (txt) in let titleWidth = (txt as NSString).size(withAttributes: nil).width (txt as NSString).draw(at: CGPoint(x: 10 + CGFloat(step * CGFloat(index))-titleWidth/2, y: startOffsetY+rectHeight), withAttributes: nil) index = index+1 } let title = "您已完成( Int(Double(total) * progress) )场比赛" let titleWidth = (title as NSString).size(withAttributes: nil).width let titleHeight = (title as NSString).size(withAttributes: nil).height var titleX = hoverX - titleWidth/2 if titleX<0 { titleX = 0 } if hoverX + titleWidth/2 > self.frame.width { titleX = self.frame.width-titleWidth } // if titleX + titleWidth >= self.frame.width { // titleX = self.frame.width-10-titleWidth // } (title as NSString).draw(at: CGPoint(x:titleX , y: startOffsetY-10-titleHeight), withAttributes: [NSAttributedString.Key.foregroundColor:forColor])
如何是不感觉这些也不是那么的难了,整个过程其实就是一个细致的拆分,当然了咱们的实例只是个简单的,但是对于后续遇到类型这个需要画进度的事情我们也可按照思路一点点拆分来实现