ios笑臉app實現
import UIKit
@IBDesignable
class FaceView: UIView {
@IBInspectable
var lineWidth:CGFloat=3{didSet{setNeedsLayout()}}
@IBInspectable
var color:UIColor = UIColor.blueColor(){didSet{setNeedsLayout()}}
@IBInspectable
var scale:CGFloat=0.9{didSet{setNeedsLayout()}}
var faceCenter:CGPoint{
return convertPoint(center, fromView: superview)
}
var faceRadius:CGFloat{
return min(bounds.size.width, bounds.size.height)/2*scale
}
private struct Scaling {
static let FaceRadiusToEyeRadiusRatio: CGFloat = 10
//大圓半徑(face半徑)與小圓半徑(eye半徑)的比率,次數越小,小圓越大.因爲 下面bezierPathForEye的方法中定義 eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
static let FaceRadiusToEyeOffsetRatio: CGFloat = 3
//大圓與小圓的偏移率,此數越大,小圓的圓心距大圓越近
static let FaceRadiusToEyeSeparationRatio: CGFloat = 1.5
//兩個小圓之間在大圓內的分離比率
static let FaceRadiusToEyeMounthWidthRatio: CGFloat = 1
static let FaceRadiusToEyeMounthHeightRatio: CGFloat = 3
static let FaceRadiusToEyeMounthOffsetRatio: CGFloat = 3
}
private enum Eye {
case Left , Right
}
private func bezierPathForEye(whichEye: Eye) -> UIBezierPath {
//此處定義的方法爲設置一隻眼睛的位置,上面定義了左右眼的枚舉,可通過調用.Left.Right來實現兩個位置的設定
let eyeRadius = faceRadius / Scaling.FaceRadiusToEyeRadiusRatio
//定義小圓半徑是大圓半徑的幾分之幾,此處因爲FaceRadiusToEyeRadiusRatio: CGFloat = 10 故爲十分之一
let eyeVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeOffsetRatio
//小圓的垂直偏距
let eyeHorizontalSeparation = faceRadius / Scaling.FaceRadiusToEyeSeparationRatio
//小圓的水平距離
var eyeCenter = faceCenter
eyeCenter.y -= eyeVerticalOffset
//此處相當於是用大圓圓心的y座標減去小圓圓心的y座標,故小圓圓心在大圓圓心之上.若爲加,則在下
switch whichEye {
case .Left: eyeCenter.x -= eyeHorizontalSeparation / 2
//相當於大圓圓心的x座標減去(小圓圓心的x座標除以2),即在大圓圓心的左側
case .Right: eyeCenter.x += eyeHorizontalSeparation / 2
//此處加,即在右側
}
let path = UIBezierPath(arcCenter: eyeCenter, radius: eyeRadius, startAngle: 0, endAngle: CGFloat(2*M_PI), clockwise: true) //畫圓
path.lineWidth = lineWidth //設定線寬
return path
}
private func bezierPathForSmile(fractionOfMaxSmile: Double) -> UIBezierPath {
let mouthWidth = faceRadius / Scaling.FaceRadiusToEyeMounthWidthRatio
//大圓半徑與線寬的比率,此處線寬=大圓半徑
let mouthHeight = faceRadius / Scaling.FaceRadiusToEyeMounthHeightRatio
//mouthHeight即線的中點到圓心的距離
let mouthVerticalOffset = faceRadius / Scaling.FaceRadiusToEyeMounthOffsetRatio
let smileHeight = CGFloat(max(min(fractionOfMaxSmile, 1), -1)) * mouthHeight
//此處max(min(fractionOfMaxSmile, 1), -1)限定了笑臉指數只能在-1到1之間,fractionOfMaxSmile這個參數可以自行設定,如果設定的大於1,則只取1,設定小於-1,則只取-1
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) //設置曲線點1,此處mouthWidth / 3用於調節曲線的弧度
let cp2 = CGPoint(x: end.x - mouthWidth / 3, y: cp1.y) //設置曲線點2
let path = UIBezierPath()
path.moveToPoint(start)
path.addCurveToPoint(end, controlPoint1: cp1, controlPoint2: cp2)
path.lineWidth = lineWidth
return path
}
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 smiliness = 0.8
let smilePath = bezierPathForSmile(smiliness)
smilePath.stroke()
}
}
- IBDesignable可以在storyboard中看到自定義的uiview
- IBInspectable使屬性可以改變
利用協議與代理聯結數據源
protocol FaceViewDataSource:class {
func smilnessForFaceView(sender:FaceView)->Double?
}
手勢識別實現縮放與改變笑臉弧度
@IBOutlet weak var faceView: FaceView!{
didSet{
faceView.dataSource=self
faceView.addGestureRecognizer(UIPinchGestureRecognizer(target: faceView, action: "scale:"))
//faceView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "changeHappiness:"))
}
}
private struct Constants{
static let HappinessGestureScale:CGFloat=4
}
@IBAction func changeHappiness(sender: UIPanGestureRecognizer) {
switch sender.state {
case .Ended:
fallthrough
case .Changed:
let translation=sender.translationInView(faceView)
let happinessChange = -Int(translation.y/Constants.HappinessGestureScale)
if happinessChange != 0{
happiness+=happinessChange
sender.setTranslation(CGPoint.zero, inView: faceView)
}
default:
break
}
}
func scale(gesture:UIPinchGestureRecognizer){
if gesture.state == .Changed{
scale*=gesture.scale
gesture.scale=1
}
}
源代碼:Happiness