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])

如何是不感覺這些也不是那麼的難了,整個過程其實就是一個細緻的拆分,當然了咱們的實例只是個簡單的,但是對於後續遇到類型這個需要畫進度的事情我們也可按照思路一點點拆分來實現