放肆地用 UIBezierPath 和 CAShapeLayer 畫各種圖形
CAShapeLayer 是 CALayer 的子類,但是比 CALayer 更靈活,可以畫出各種圖形,當然,你也可以使用其他方式來畫,隨你。
雜談
在 CAShapeLayer 中,也可以像 CALayer 一樣指定它的 frame 來畫,就像這樣:
Objective-C12345 | let layer=CAShapeLayer()layer.frame=CGRectMake(110,100,150,100)layer.backgroundColor=UIColor.blackColor().CGColorview.layer.addSublayer(layer) |
然後你就會得到如圖這樣的黑色矩形
但是,CAShapeLayer 有一個神奇的屬性 path
用這個屬性配合上 UIBezierPath 這個類就可以達到超神的效果。
UIBezierPath 顧名思義,這是用貝塞爾曲線的方式來構建一段弧線,你可以用任意條弧線來組成你想要的形狀,比如,你想用它來和上面一樣畫一個矩形,那就可以這樣子來做:
12345 | let path=UIBezierPath |
要注意的是,這裡就不要用backgroundColor
這個屬性了,而要使用 fillColor
和 strokeColor
,前者代表設定這個 Layer 的填充色,後者代表設定它的邊框色
12 | layer.fillColor=UIColor.clearColor().CGColorlayer.strokeColor=UIColor.blackColor().CGColor |
可以試一下把上面程式碼設定顏色的部分改成這個樣子,那麼執行程式的時候就會是這種樣子
玩一下UIBezierPath
在說回 UIBezierPath ,在 UIBezierPath 的 init 方法中,就有很多方便你畫各種圖形的方法,比如你可以畫一個帶圓角的圖形
Objective-C12345 | let path=UIBezierPath(roundedRect: CGRectMake(110,100,150,100),cornerRadius:50)let layer=CAShapeLayer()layer.path=path.CGPathlayer.fillColor=UIColor.clearColor().CGColorlayer.strokeColor=UIColor.blackColor().CGColor |
還可以指定起始角和半徑畫圓
Objective-C12345678 | letradius: CGFloat=60.0letstartAngle: CGFloat=0.0letendAngle: CGFloat=CGFloat(M_PI*2)let path=UIBezierPath(arcCenter: view.center,radius: radius,startAngle: startAngle,endAngle: endAngle,clockwise: true)let layer=CAShapeLayer()layer.path=path.CGPathlayer.fillColor=UIColor.clearColor().CGColorlayer.strokeColor=UIColor.blackColor().CGColor |
在這裡涉及到角度的問題,起始角和結束角,這裡的角度使使用弧度制來表示,這裡我收藏了一張圖片,以方便參考
怎麼畫曲線
貝塞爾曲線的畫法是由起點、終點、控制點三個引數來畫的,為了解釋清楚這個點,我寫了幾行程式碼來解釋它
Objective-C123456789101112131415161718192021222324252627282930 | let startPoint=CGPointMake(50,300)let endPoint=CGPointMake(300,300)let controlPoint=CGPointMake(170,200)let layer1=CALayer()layer1.frame=CGRectMake(startPoint.x,startPoint.y,5,5)layer1.backgroundColor=UIColor.redColor().CGColorlet layer2=CALayer()layer2.frame=CGRectMake(endPoint.x,endPoint.y,5,5)layer2.backgroundColor=UIColor.redColor().CGColorlet layer3=CALayer()layer3.frame=CGRectMake(controlPoint.x,controlPoint.y,5,5)layer3.backgroundColor=UIColor.redColor().CGColorlet path=UIBezierPath()let layer=CAShapeLayer()path.moveToPoint(startPoint)path.addQuadCurveToPoint(endPoint,controlPoint: controlPoint)layer.path=path.CGPathlayer.fillColor=UIColor.clearColor().CGColorlayer.strokeColor=UIColor.blackColor().CGColorview.layer.addSublayer(layer)view.layer.addSublayer(layer1)view.layer.addSublayer(layer2)view.layer.addSublayer(layer3) |
我很隨意的定義了三個點,為了清楚顯示它們的位置,我放了三個矩形在上面以便觀察,然後呼叫 path.moveToPoint(startPoint)
讓它移動到起始點,然後呼叫path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint)
這個方法告訴它結束點和控制點,這樣它就能畫出一條有弧度的線條了,如果把fillColor
設定一個顏色,那麼它就會變成一個很醜的形狀了,示例圖如下
控制點決定了它的曲率,曲線的頂點不等於控制點的位置,具體可以看一下貝塞爾曲線的定義,你還可以使用兩個控制點來畫,兩個控制點可以使用方法 path.addCurveToPoint(endPoint, controlPoint1: controlPoint, controlPoint2: controlPoint2)
來搞定
這樣它會是這個樣子
再來說說 CAShapeLayer
CAShapeLayer 是個神奇的東西,給它一個path
它就能變成你想要的形狀,它還有很多可以玩的地方。綜合使用可以組合成不同的動畫,比如下面這樣:
這三個動畫就是使用了 strokeEnd
strokeStart
lineWidth
三個屬性,第一個動畫用了strokeEnd
這個屬性的值範圍是0-1,動畫顯示了從0到1之間每一個值對這條曲線的影響,strokeStart
的方法則是相反的,如果把這兩個值首先都設定成0.5然後慢慢改變成0和1的時候就會變成第二個動畫,配合lineWidth
則曲線會慢慢變粗,這裡的很多屬性都是支援動畫的。
示例程式碼
Objective-C123456789101112131415161718192021222324252627282930313233 | private func animation1(){let animation=CABasicAnimation(keyPath:"strokeEnd")animation.fromValue=0animation.toValue=1animation.duration=2layer.addAnimation(animation, forKey:"")}private func animation2(){layer.strokeStart=0.5layer.strokeEnd=0.5let animation=CABasicAnimation(keyPath:"strokeStart")animation.fromValue=0.5animation.toValue=0animation.duration=2let animation2=CABasicAnimation(keyPath:"strokeEnd")animation2.fromValue=0.5animation2.toValue=1animation2.duration=2layer.addAnimation(animation, forKey:"")layer.addAnimation(animation2, forKey:"")}private func animation3(){let animation=CABasicAnimation(keyPath:"lineWidth")animation.fromValue=1animation.toValue=10animation.duration=2layer.addAnimation(animation,forKey:"")} |
應用一下
前一陣子在仿時光網這個APP,其中有一個Layer的形狀很怪異,是這樣的
很明顯它可以用 CAShapeLayer + UIBezierPath 來做,思路大概是這樣,先移動到左上方的位置,然後向下劃線,然後往右劃線,然後往上劃線,還剩一個蓋子,這個蓋子就用一個控制點控制曲率,非常簡單,程式碼如下
Objective-C12345678910111213 | let finalSize=CGSizeMake(CGRectGetWidth(view.frame),400)let layerHeight=finalSize.height *0.2let layer=CAShapeLayer()let bezier=UIBezierPath()bezier.moveToPoint(CGPointMake(0,finalSize.height-layerHeight))bezier.addLineToPoint(CGPointMake(0,finalSize.height-1))bezier.addLineToPoint(CGPointMake(finalSize.width,finalSize.height-1))bezier.addLineToPoint(CGPointMake(finalSize.width,finalSize.height-layerHeight))bezier.addQuadCurveToPoint(CGPointMake(0,finalSize.height-layerHeight),controlPoint: CGPointMake(finalSize.width/2,(finalSize.height-layerHeight)-40))layer.path=bezier.CGPathlayer.fillColor=UIColor.blackColor().CGColorview.layer.addSublayer(layer) |
就能畫出這樣的形狀來
再來一個複雜點的,微信下拉拍小視訊的那隻眼睛很有趣,來模仿一下那個效果吧,它是這樣的
首先你得畫出這隻眼睛,這是眼睛包括5個部分組成(這個是用OC寫的)
Objective-C