1. 程式人生 > >iOS 動畫Animation - 5:UIBezier

iOS 動畫Animation - 5:UIBezier

過多 ack 方便 nsf word ins ali seve 畫圓

首先說明:這是一系列文章,參考本專題下其它的文章有助於你對本文的理解。

在之前的bolg中大家會發現總是會出現UIBezier,可是我也沒有做過多介紹,今天就集中介紹一下UIBezier。首先。UIBezier的內容比較多,我今天介紹的也不是UIBezier的所有,可是大部分經常使用到的我都會介紹一下。至於其它的,請大家參考官方文檔。

由於今天的內容比較多。也可能有些地方不是非常easy理解,我會盡量的把他介紹的看起來簡單一些,方便學習。

首先上一張圖,你就會看到今天要講到的內容
技術分享圖片

這就是今天要講到的內容。我會教大家將如圖所看到的的圖形都繪制下來。

首先我們須要創建一個UIView類。對這個UIView類做繪制操作

技術分享圖片

我創建的UIView類教PathView,然後在ViewController裏創建他的對象

//創建一個PathView
let pathView = PathView()
pathView.frame = CGRect(x: 50, y: 0, width: 350, height: 550)
view.addSubview(pathView)

然後剩下的操作都是在這個PathView裏了,在drawRect方法裏對視圖進行繪制


一次貝塞爾曲線

一次貝塞爾曲線比較簡單,相信大家都看得懂

五邊形

    func creatPentagonPath() {

        let path = UIBezierPath()
        path.lineWidth = 2.0 //線寬
        //設置起點
        path.moveToPoint(CGPoint(x: 70.0, y: 20.0))
        //設置拐角點
        path.addLineToPoint(CGPoint(x: 120.0, y: 40.0))
        path.addLineToPoint(CGPoint(x: 100.0, y: 90.0
)) path.addLineToPoint(CGPoint(x: 40.0, y: 90.0)) path.addLineToPoint(CGPoint(x: 20.0, y: 40.0)) //最後閉合 path.closePath() path.stroke()//描邊樣式 //path.fill()//填充樣式 }

解釋:這是最簡單的一個UIBezier。path.moveToPoint()和path.closePath()作為起點和閉合曲線是必須的,中間的addLineToPoint就是加入各個點。在這裏加入的五個點組成的圖形是一個五邊形。

path.stroke()和path.fill()差別就是一個是描邊樣式,一個是填充樣式。之前的bolg裏有講到strok和fill的差別。

矩形

矩形有專門的初始化方法。不用再手動的繪制

    func creatRectanglePath() {
        //創建bezier路徑
        let path = UIBezierPath(rect: CGRect(x: 220, y: 30, width: 100, height: 50))
        path.lineCapStyle = .Round //線類型
        path.lineJoinStyle = .Miter //拐角類型
        path.lineWidth = 2.0//設置線寬
        path.stroke()//描邊樣式
        //path.fill()//填充樣式
    }

解釋:這個也簡單。rect就是矩形。path.lineCapStyle是線類型,path.lineJoinStyle是拐角類型,跟之前將CAShapeLayer裏有一些屬性比較類似。能夠參考,鏈接:iOS 動畫Animation-4-3: CALayer子類:CAShapeLayer

橢圓

也能夠用來畫圓。內切於正方形的時候就是圓了

    func creatOvalPath() {
        //畫出來的橢圓為ovalInRect畫出的矩形的內切橢圓
        let path = UIBezierPath(ovalInRect: CGRect(x: 20, y: 120, width: 100, height: 50))
        path.lineWidth = 2
        path.fill()
    }

解釋:這個有沒有看起來更簡單呢,就初始化方式不一樣而已,ovalInRect就代表的是橢圓而且是內切與rect的橢圓

圓弧

    func creatArcPath() {
        let path = UIBezierPath(arcCenter: CGPoint(x: 270, y: 120), radius: 50, startAngle: 0, endAngle: CGFloat(M_PI), clockwise: true)
        path.lineWidth = 2
        path.stroke()
    }

解釋:當中的參數分別指定:這段圓弧的中心,半徑,開始角度,結束角度,是否順時針方向。


二次貝塞爾曲線

這就比一次貝塞爾曲線略微復雜一下了。二次貝塞爾曲線的特點就是會有一個控制點

    func creatQuadCurvePath() {
        let path = UIBezierPath()
        //設置起點
        path.moveToPoint(CGPoint(x: 20, y: 210))
        //參數分別指終點,中間控制點
        path.addQuadCurveToPoint(CGPoint(x: 120, y: 210), controlPoint: CGPoint(x: 70, y: 180))
        //加入圓弧, 參數依次為中心點, 半徑, 開始角度, 結束角度, 是否順時針
        path.addArcWithCenter(CGPoint(x: 70, y: 210), radius: 50, startAngle: 0.0, endAngle: CGFloat(M_PI), clockwise: true)
        path.lineWidth = 2
        path.stroke()
    }

解釋:感覺凝視都寫的非常具體了path.addQuadCurveToPoint這就是二次貝塞爾曲線。是有一個控制點(第二個參數)控制這條曲線的彎曲程度,第一個參數是終點,當然另一個path.moveToPoint作為起點。


通過以下這張圖。具體大家都清晰了二次貝塞爾曲線的各個參數是作什麽用的了
技術分享圖片


三次貝塞爾曲線

    func creatCurvePath() {
        let path = UIBezierPath()
        //起點
        path.moveToPoint(CGPoint(x: 220, y: 230))
        //參數分別指終點,中間控制點
        path.addCurveToPoint(CGPoint(x: 320, y: 220), controlPoint1: CGPoint(x: 250, y: 200), controlPoint2: CGPoint(x: 290, y: 250))
        path.lineWidth = 2
        path.stroke()
    }

解釋:能夠看到三次貝塞爾曲線就是比二次貝塞爾曲線多了一個控制點。關系圖例如以下圖所看到的
技術分享圖片


以下再簡單的涉足一下Core Graphics

單一改動CGPath

     func creatSingleCGPath() {
        //創建可變CGPath
        let cgPath = CGPathCreateMutable()
        CGPathAddEllipseInRect(cgPath, nil, CGRect(x: 20, y: 270, width: 100, height: 50))
        CGPathAddEllipseInRect(cgPath, nil, CGRect(x: 45, y: 282.5, width: 50, height: 25))
        let path = UIBezierPath()
        path.CGPath = cgPath
        path.usesEvenOddFillRule = true
        path.lineWidth = 2
        path.stroke()
//        CGPathRelease(cgPath);假設是OC須要運行這句代碼
    }

解釋:創建可變Path通過Core Graphics函數來改動Path

CGPath與UIBezierPath混合使用

    func creatMixCGPathAndUIBezierPath() {
        //創建貝塞爾曲線
        let path = UIBezierPath(ovalInRect: CGRect(x: 220, y: 270, width: 100, height: 50))
        //獲取CGPath
        let cgPath = path.CGPath
        //copy給可變CGPath
        let mutablePath = CGPathCreateMutableCopy(cgPath)! as CGMutablePathRef
        //設置起點
        CGPathMoveToPoint(mutablePath, nil, 245, 295)
        //加入曲線
        //參數cp1x實際上是controlPoint1.x的縮寫,所以參數為,控制點1,控制點2,終點
        CGPathAddCurveToPoint(mutablePath, nil, 255, 270, 285, 320, 295, 295)
        //其它函數
        /*
        //加入直線
        CGPathAddLineToPoint(<#T##path: CGMutablePath?##CGMutablePath?#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##x: CGFloat##CGFloat#>, <#T##y: CGFloat##CGFloat#>)
        //參數1,點的數組,參數2:count要繪制的點的個數
        CGPathAddLines(<#T##path: CGMutablePath?

##CGMutablePath?

#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##points: UnsafePointer<CGPoint>##UnsafePointer<CGPoint>#>, <#T##count: Int##Int#>) //加入路徑 CGPathAddPath(<#T##path1: CGMutablePath?##CGMutablePath?#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##path2: CGPath?

##CGPath?

#>) //加入二次路徑 CGPathAddQuadCurveToPoint(<#T##path: CGMutablePath?

##CGMutablePath?#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##cpx: CGFloat##CGFloat#>, <#T##cpy: CGFloat##CGFloat#>, <#T##x: CGFloat##CGFloat#>, <#T##y: CGFloat##CGFloat#>) //加入矩形 CGPathAddRect(<#T##path: CGMutablePath?##CGMutablePath?

#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##rect: CGRect##CGRect#>) CGPathAddRects(<#T##path: CGMutablePath?##CGMutablePath?#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##rects: UnsafePointer<CGRect>##UnsafePointer<CGRect>#>, <#T##count: Int##Int#>) CGPathAddRoundedRect(<#T##path: CGMutablePath?##CGMutablePath?#>, <#T##transform: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##rect: CGRect##CGRect#>, <#T##cornerWidth: CGFloat##CGFloat#>, <#T##cornerHeight: CGFloat##CGFloat#>) //加入圓弧 CGPathAddArc(<#T##path: CGMutablePath?

##CGMutablePath?#>, <#T##m: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##x: CGFloat##CGFloat#>, <#T##y: CGFloat##CGFloat#>, <#T##radius: CGFloat##CGFloat#>, <#T##startAngle: CGFloat##CGFloat#>, <#T##endAngle: CGFloat##CGFloat#>, <#T##clockwise: Bool##Bool#>) CGPathAddRelativeArc(<#T##path: CGMutablePath?

##CGMutablePath?#>, <#T##matrix: UnsafePointer<CGAffineTransform>##UnsafePointer<CGAffineTransform>#>, <#T##x: CGFloat##CGFloat#>, <#T##y: CGFloat##CGFloat#>, <#T##radius: CGFloat##CGFloat#>, <#T##startAngle: CGFloat##CGFloat#>, <#T##delta: CGFloat##CGFloat#>) */ path.CGPath = mutablePath path.lineWidth = 2 path.stroke() }

解釋:這裏內容比較多。我就不一一解釋了。事實上方法內容跟上面介紹的都比較類似。

參數也基本和上面介紹的一樣。細致看的話都能看懂什麽意思。

內容控制(附加)

    func setUpContext() {
        let path = UIBezierPath(ovalInRect: CGRect(x: 20, y: 350, width: 100, height: 50))
        UIColor.redColor().setStroke()
        UIColor.orangeColor().setFill()
        let ref = UIGraphicsGetCurrentContext()
        //內容平移
        CGContextTranslateCTM(ref, 20, 20)
        //內容旋轉
        //由於我把所有圖形畫在同一個視圖中,anchorPoint並不是當前橢圓的中心, 所以旋轉後當前橢圓會偏離所在位置
        CGContextRotateCTM(ref, CGFloat(-M_PI_4/4));
        //內容縮放
        CGContextScaleCTM(ref, 0.8, 1.0)
        path.lineWidth = 2
        path.fill()
        path.stroke() 
    }

解釋:事實上關於內容控制的又會是一大塊的內容,我就不在這裏做具體介紹了。

加大。昨天忘了將Demo放上來了,真是對不起各位觀眾了,盡管我知道沒有多少回頭客,可是還得道下歉。Demo地址

iOS 動畫Animation - 5:UIBezier