咱們不直接在HappinessViewController(根視圖控制器) 中實現,而是將FaceView徹底獨立出來,這正是遵循了MVC的設計原則。咱們主要經過貝塞爾曲線來實現表情的繪製。git
注:@IBDesignable:Xcode6 的發佈,蘋果爲開發者構建自定義控件推出了新功能IBDesignable和IBInspectable,容許在IB中實時預覽設計成果。這會給實際開發提高很高效率。IBDesignable做用在於可使改視圖在IB中實時預覽。github
//能夠在IB中預覽 @IBDesignable class FaceView: UIView { }
定義線寬、線顏色、縮放係數swift
特別的:我另外定義了一個自定義參數——幸福指數。他的範圍是-1~1。 app
注:@IBInspectable:將自定義的屬性在IB中顯示,以便咱們更方便的控制其屬性,達到動態預覽的效果。ide
@IBInspectable //線的寬度 var lineWidth : CGFloat = 3 { didSet {setNeedsDisplay() } } @IBInspectable //線的顏色 var color : UIColor = UIColor.blueColor() { didSet {setNeedsDisplay() } } @IBInspectable //表情縮放係數 var scale : CGFloat = 0.90 {didSet { setNeedsDisplay() } } @IBInspectable //微笑程度(幸福指數) var smiliness : Double = 0.75 {didSet { setNeedsDisplay() } }
咱們採用結構體來規定咱們想要的參數。以下所示:spa
private struct Scaling { static let FaceRadiusToEyeRadiusRatio:CGFloat = 10//眼睛彎曲半徑比例 static let FaceRadiusToEyeOffsetRatio:CGFloat = 3//眼睛偏移比例 static let FaceRadiusToEyeSeparationRatio:CGFloat = 1.5//眼睛間隙比例 static let FaceRadiusToMouthWidthRatio:CGFloat = 1//嘴寬度比例 static let FaceRadiusToMouthHeightRatio:CGFloat = 3//嘴高度比例 static let FaceRadiusToMouthOffsetRatio:CGFloat = 3//嘴便宜比例 }
private enum Eye { case Left, Right }
//在父視圖上的中心座標 var faceCenter:CGPoint { get{ return convertPoint(center, fromView: superview) } }
var faceRadius:CGFloat { get{ return scale * min(bounds.size.width,bounds.size.height) / 2 } }
固然是先畫臉(圓),經過UIBezierPath類方法來畫(建立路徑對象)一個圓(路徑)。設計
//arcCenter: 圓心 //radius:半徑 //startAngle:起點角度 //endAngle:終點角度 let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true)
設置顏色寬度。code
//線的寬度 facePath.lineWidth = lineWidth //線的顏色 color.set()
最後別忘了調用stroke(),將這個路徑畫出來。對象
//最終將它"畫"出來 facePath.stroke()
咱們封裝一下畫眼睛這部分代碼,經過傳入眼睛左右的枚舉值來畫。 眼睛實質仍是畫圓,只是否是完整的圓,咱們只須要根據左右找到其中心、半徑及起始角度就行了。開發
//眼睛 private func bezierPathForEye(whichEye: Eye) -> UIBezierPath { //計算眼睛的半徑 let eyeRadius = faceRadius/Scaling.FaceRadiusToEyeRadiusRatio //計算眼睛垂直的偏移量 let eyeVerticalOffset = faceRadius/Scaling.FaceRadiusToEyeOffsetRatio //計算眼睛水平的距離 let eyeHorizontalSeparation = faceRadius/Scaling.FaceRadiusToEyeSeparationRatio //眼睛中心 var eyeCenter = faceCenter //y值是一致的 eyeCenter.y -= eyeVerticalOffset //根據左右來計算 眼的圓心x座標 switch whichEye { case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2 case .Right: eyeCenter.x += eyeHorizontalSeparation / 2 } //調用上面用過的UIBezierPath畫圓的類方法來畫圓 let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true) //線的寬 path.lineWidth = lineWidth //最後返回路徑 return path }
嘴能夠用曲線來畫。使用UIBezierPath對象的方法:addCurveToPoint,來畫曲線。須要計算的值有、起始點、控制點。
//微笑 private func bezierPathForSmile(fractionOfMaxSmile : Double) -> UIBezierPath { //嘴寬 let mouthWidth = faceRadius/Scaling.FaceRadiusToMouthWidthRatio //嘴高 let mouthHeight = faceRadius/Scaling.FaceRadiusToMouthHeightRatio //嘴垂直偏移 let mouthVerticalOffset = faceRadius/Scaling.FaceRadiusToMouthOffsetRatio //微笑高度 let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight //開始點 let start = CGPoint(x: faceCenter.x - mouthWidth / 2, y: faceCenter.y + mouthVerticalOffset) //結束點 let end = CGPoint(x: start.x + mouthWidth, y: start.y) //第一個控制點 let cp1 = CGPoint(x: start.x + mouthWidth / 3, y: start.y + smileHeight) //第二個控制點 let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y) let path = UIBezierPath() //路徑移至起點 path.moveToPoint(start) //增長路徑的終點、控制點 path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2) path.lineWidth = lineWidth return path }
其中控制點cp一、cp2能夠經過下圖來理解:
在重繪中調用以上方法,具體以下:
override func drawRect(rect: CGRect){ //圓圓的臉 let facePath = UIBezierPath(arcCenter: faceCenter, radius: faceRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true) facePath.lineWidth = lineWidth color.set() facePath.stroke() //一雙大眼 bezierPathForEye(.Left).stroke() bezierPathForEye(.Right).stroke() //嘴 let smilePath = bezierPathForSmile(smiliness) smilePath.stroke() }
打開SB(故事版)、點擊FaceView,能夠在右側屬性欄中看到,咱們自定義的屬性已經綁定在右邊了,咱們能夠手動更改,在IB中實時預覽輸出效果!像下面這樣:
試着更改一下寬度,我改成20,發下臉皮真的變厚了呢?
試着更改顏色,我改成黑色,好吧咱們都不喜歡黑臉!
試着改一下縮放比例,改成0.5,好吧臉變小了:
最後咱們試着調一下,幸福指數:
咱們發現幸福指數爲1的時候是這樣的:
0變成了直線,而-1變成了難過的表情:
Github: