UIBezierPath 繪製可愛圖案-盜版Sally

想必大家都很常使用Line, 我就想到使用Line貼圖來當作這次的主題

先來介紹一下我最喜歡的貼圖之一~

莎莉 (Sally)
雞/女
生日︰4月27日
喜歡的東西︰大吃大喝、變強壯
討厭的東西︰難吃的食物、背誦或思考事情
特點:單純、無知
Reference Source: LINE Corp

先來看看正版莎莉

再來看看盜版莎莉

覺得正版的Sally在哭 XDDD

真的是有點難刻畫出來,或許需要時間來調適吧XD

盜版莎莉製作時間約3~4小時

看看程式碼

宣告區

let degree = CGFloat.pi/180let head = UIBezierPath()let headR:CGFloat = 120   //為head的半徑let headCoordinateX:CGFloat = 230 //為中心座標let headCoordinateY:CGFloat = 175 //為中心座標let body = UIBezierPath()let bodyR:CGFloat = 120     //為body的半徑let bodyCoorXShift:CGFloat = 20  //為head到body的offsetlet bodyCoorYShift:CGFloat = 100  //為head到body的offsetlet leftHand = UIBezierPath()let leftHand2 = UIBezierPath()let rightHand = UIBezierPath()let handR:CGFloat = 25           //為hand的長度,後面以此類推let leftFoot = UIBezierPath()let rightFoot = UIBezierPath()let footR:CGFloat = 50let mouse = UIBezierPath()let mouseLine = UIBezierPath()let leftEye = UIBezierPath()let rightEye = UIBezierPath()let eyeR:CGFloat = 20

Class類別區(身體手腳嘴巴眼睛)

class BodyView: UIView{
override func draw(_ rect: CGRect) {
head.addArc(withCenter: CGPoint(x: headCoordinateX, y: headCoordinateY), radius: headR, startAngle: degree*0, endAngle: degree*360, clockwise: true)
body.addArc(withCenter: CGPoint(x: headCoordinateX+bodyCoorXShift, y: headCoordinateY+bodyCoorYShift), radius: bodyR, startAngle: degree*0, endAngle: degree*360, clockwise: true)
head.append(body)
UIColor.black.setStroke()
head.lineWidth = 3
head.stroke()
UIColor(red: 255/255, green: 217/255, blue: 59/255, alpha: 1).setFill()
head.fill()
}
}
class EyesView: UIView{
override func draw(_ rect: CGRect) {
leftEye.addArc(withCenter: CGPoint(x: headCoordinateX-27, y: headCoordinateY-60), radius: eyeR, startAngle: degree*0, endAngle: degree*360, clockwise: true)
rightEye.addArc(withCenter: CGPoint(x: headCoordinateX+27, y: headCoordinateY-60), radius: eyeR, startAngle: degree*0, endAngle: degree*360, clockwise: true)
leftEye.append(rightEye)
UIColor.black.setFill()
leftEye.fill()
}
}
class MouseView: UIView{
override func draw(_ rect: CGRect) {
mouse.move(to: CGPoint(x: headCoordinateX-65, y: headCoordinateY))
mouse.addCurve(to: CGPoint(x: headCoordinateX+65, y: headCoordinateY),
controlPoint1: CGPoint(x: headCoordinateX-40, y: headCoordinateY-40),
controlPoint2: CGPoint(x: headCoordinateX+40, y: headCoordinateY-40))
mouse.move(to: CGPoint(x: headCoordinateX-65, y: headCoordinateY))
mouse.addCurve(to: CGPoint(x: headCoordinateX+65, y: headCoordinateY),
controlPoint1: CGPoint(x: headCoordinateX-40, y: headCoordinateY+40),
controlPoint2: CGPoint(x: headCoordinateX+40, y: headCoordinateY+40))
UIColor(red: 255/255, green: 77/255, blue: 0/255, alpha: 1).setStroke()
mouse.lineWidth = 10
mouse.stroke()
UIColor(red: 255/255, green: 102/255, blue: 0/255, alpha: 1).setFill()
mouse.fill()

mouseLine.move(to: CGPoint(x: headCoordinateX-65, y: headCoordinateY))
mouseLine.addLine(to: CGPoint(x: headCoordinateX+50, y: headCoordinateY))
UIColor(red: 255/255, green: 77/255, blue: 0/255, alpha: 1).setStroke()
mouseLine.lineWidth = 7
mouseLine.stroke()

}
}
class LeftHandView: UIView{
override func draw(_ rect: CGRect) {

leftHand.move(to: CGPoint(x: headCoordinateX-110, y: headCoordinateY+(bodyCoorYShift/2)))
leftHand.addLine(to: CGPoint(x: headCoordinateX-140-handR, y: headCoordinateY+20))
leftHand.close()
UIColor.black.setStroke()
leftHand.stroke()

leftHand2.move(to: CGPoint(x: headCoordinateX-110, y: headCoordinateY+(bodyCoorYShift/2)))
leftHand2.addArc(withCenter: CGPoint(x: headCoordinateX-110+20, y: headCoordinateY+(bodyCoorYShift/2)-10), radius: 3*handR, startAngle: degree*210, endAngle: degree*83, clockwise: false)
UIColor.black.setStroke()
leftHand2.lineWidth = 3
leftHand2.stroke()
UIColor(red: 255/255, green: 217/255, blue: 59/255, alpha: 1).setFill()
leftHand2.fill()
}
}
class RightHandView: UIView{
override func draw(_ rect: CGRect) {
rightHand.move(to: CGPoint(x: headCoordinateX+130, y: headCoordinateY+(bodyCoorYShift/2)))
rightHand.close()
UIColor.black.setStroke()
rightHand.stroke()

rightHand.move(to: CGPoint(x: headCoordinateX+150, y: headCoordinateY+(bodyCoorYShift/2)))
rightHand.addArc(withCenter: CGPoint(x: headCoordinateX+110+20, y: headCoordinateY+(bodyCoorYShift/2)-10), radius: 3*handR, startAngle: degree*0, endAngle: degree*135, clockwise: true)

rightHand.addQuadCurve(to: CGPoint(x: headCoordinateX+140+50, y: headCoordinateY+(bodyCoorYShift/2)), controlPoint: CGPoint(x: headCoordinateX+110+20, y: headCoordinateY+(bodyCoorYShift/2)-10))

UIColor.black.setStroke()
rightHand.lineWidth = 3
rightHand.stroke()
UIColor(red: 255/255, green: 217/255, blue: 59/255, alpha: 1).setFill()
rightHand.fill()
}
}
class LeftFootView: UIView{
override func draw(_ rect: CGRect) {
leftFoot.move(to: CGPoint(x: headCoordinateX, y: headCoordinateY+(bodyCoorYShift*2+20)))
leftFoot.addLine(to: CGPoint(x: headCoordinateX, y: headCoordinateY+(bodyCoorYShift*2+20)+footR))

leftFoot.addCurve(to: CGPoint(x: headCoordinateX, y: headCoordinateY+(bodyCoorYShift*2+20)),
controlPoint1: CGPoint(x: headCoordinateX-2*footR, y: headCoordinateY+(bodyCoorYShift*2+20)+footR),
controlPoint2: CGPoint(x: headCoordinateX+2*footR, y: headCoordinateY+(bodyCoorYShift*2+20)+3*footR))
leftFoot.close()
UIColor.black.setStroke()
leftFoot.lineWidth = 3
leftFoot.stroke()
UIColor(red: 255/255, green: 77/255, blue: 59/255, alpha: 1).setFill()
leftFoot.fill()
}
}
class RightFootView: UIView{
override func draw(_ rect: CGRect) {
rightFoot.move(to: CGPoint(x: headCoordinateX+60, y: headCoordinateY+(bodyCoorYShift*2+20)))
rightFoot.addLine(to: CGPoint(x: headCoordinateX+60, y: headCoordinateY+(bodyCoorYShift*2+20)+footR))

rightFoot.addCurve(to: CGPoint(x: headCoordinateX+60, y: headCoordinateY+(bodyCoorYShift*2+20)),
controlPoint1: CGPoint(x: headCoordinateX+60-2*footR, y: headCoordinateY+(bodyCoorYShift*2+20)+footR),
controlPoint2: CGPoint(x: headCoordinateX+60+2*footR, y: headCoordinateY+(bodyCoorYShift*2+20)+3*footR))
rightFoot.close()
UIColor.black.setStroke()
rightFoot.lineWidth = 3
rightFoot.stroke()
UIColor(red: 255/255, green: 77/255, blue: 59/255, alpha: 1).setFill()
rightFoot.fill()
}
}
}

主程式區

let showFrame = CGRect(x: 0, y: 0, width: 500, height: 500)let bodyView = BodyView(frame: showFrame)
let eyeView = EyesView(frame: showFrame)
let mouseView = MouseView(frame: showFrame)
let leftHandView = LeftHandView(frame: showFrame)
let rightHandView = RightHandView(frame: showFrame)
let leftFootView = LeftFootView(frame: showFrame)
let rightFootView = RightFootView(frame: showFrame)
bodyView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
eyeView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
mouseView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
leftHandView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
rightHandView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
leftFootView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
rightFootView.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 0)
bodyView.addSubview(eyeView)
bodyView.addSubview(mouseView)
bodyView.addSubview(leftHandView)
bodyView.addSubview(rightHandView)
bodyView.addSubview(leftFootView)
bodyView.addSubview(rightFootView)

算是把所有程式都疊加到bodyView上面去

所以bodyView.backgroundColor會先給他個底色,這邊是白色且alpha為1,其他欲疊加的View.backgroundColor則是把alpha設為0,這樣就可以慢慢疊加上去囉~

當出現奇怪現象,例如說圖沒跑出來,看是不是忘記把.close()起來了,沒關起來,再怎麼.fill()都沒用囉!

另外會Override func draw()主要是因為,畫的圖需要外框線XD,所以只能Override囉!

另外本程式是在playground上執行,不需開專案檔。

再來介紹一下基本語法和使用說明:

(一)MASK遮罩法!

typealias cgp = CGPoint  //自訂型別意思,其實是懶得打那麼多字XDlet path = UIBezierPath()let path2 = UIBezierPath()path.move(to: cgp(x: 0, y: 0))   //所謂的歸零path.addLine(to: cgp(x: 150, y: 0))path.addLine(to: cgp(x: 50, y: 200))path.close()  //三點連一線path2.move(to:CGPoint(x: 100 , y: 100))path2.addLine(to: cgp(x: 0, y: 100))path2.addLine(to: cgp(x: 75, y: 0))path2.close()path.append(path2)   //裡面最重要的一行,這樣才可以加入遮罩行列,就像加入陣列元素一樣let triangleLayer = CAShapeLayer()triangleLayer.path = path.cgPath let frame = CGRect(x: 0, y: 0, width: 300, height: 300) let view = UIView(frame: frame)view.backgroundColor = UIColor(red: 10, green: 0, blue: 0, alpha: 1)view.layer.mask = triangleLayer  //也是重要的一行,把剛剛畫的兩個三角型當做遮色版,而正方形則為底圖。view  //秀畫面//補充: 快速加入四方形(cornerRadius為圓角變數)
let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 100, height: 50), cornerRadius: 5)
//補充2 自訂四方型出現端點(範例為左下和右下)
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 50), byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 3, height: 0))
//補充3 橢圓形
let path = UIBezierPath(ovalIn: CGRect(x: 30, y: 30, width: 100, height: 130))
//補充4 拱橋形 圓心(200,200),外圓R100,內圓R50
從(300,200)畫到(100,200)->在畫到(150,200)->再畫內圓(150,200)->(250,200)
let path = UIBezierPath(arcCenter: CGPoint(x: 200, y: 200), radius: 100, startAngle: aDegree * 0, endAngle: aDegree * 180, clockwise: false)
path.move(to: cgp(x: 150, y: 200))path.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 50, startAngle: aDegree*180, endAngle: aDegree*0, clockwise: true)path.close() //記得關閉!//範例5 曲線(to:代表從圓形兩個端點各拉一條線到to座標,然後在以controlPoint當成第二個點,從最靠近ControlPoint的一個"端點"和"To點"拉出曲線。)
let path = UIBezierPath(arcCenter: CGPoint(x: 200, y: 200), radius: 100, startAngle: aDegree*0, endAngle: aDegree*180, clockwise: true)
path.addQuadCurve(to: CGPoint(x: 200, y: 100), controlPoint: CGPoint(x: 100, y: 30))//雙曲線 依樣方法,只是有兩個點來控制曲線path.addCurve(to: CGPoint(x: 0, y: 50), controlPoint1: CGPoint(x: 50, y: 80), controlPoint2: CGPoint(x: 50, y: 20))

以下為原汁原味的PeterPan教學~

(二)addSublayer

非常的簡單,一句話

在View後面取(.layer屬性)(.addSublayer方法)再加上CAShapeLayer()物件名即可囉。

view.layer.addSublayer(triangleLayer)

(三)Define Class Method(自定義Class)用於畫邊框

自訂class並Override func draw(),其他做法一樣

呼叫時候也一樣,創造一個物件並指定Class~

class demoDraw: UIView{
override func draw(_ rect: CGRect) {
let dpath = UIBezierPath()
dpath.move(to: cgp(x: 0, y: 0))
dpath.addLine(to: cgp(x: 100, y: 0))
dpath.addLine(to: cgp(x: 50, y: 150))
dpath.close()
UIColor(red: 0, green: 1, blue: 0, alpha: 1).setFill() //設定填充顏色
dpath.fill() //填充該顏色(預設黑色)
}
}
let squareView = demoDraw(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
squareView.backgroundColor = UIColor.red

另外UIColor也可以使用.setFill()來設定填充顏色,記得加上IBezierPath()物件.fill()來設定填充

或是使用.setStroke()來設定邊框顏色或.lineWidth=X來設定框架寬度,記得加上UIBezierPath()物件.stroke()來設定為邊框

續前面程式碼
UIColor(red: 0, green: 1, blue: 0, alpha: 1).setStroke()
dpath.lineWidth = 5
dpath.stroke()

查詢欲製作的圖片顏色RGB和座標

https://yangcha.github.io/iview/iview.html

--

--