關於貝塞爾曲線,網上相關的文章很多,這里我主要想用更簡單的方法讓大家理解貝塞爾曲線,當然,這僅僅是我個人的理解,如有錯誤的地方還請大家能夠幫忙指出來,這樣大家才能一起進步。
貝塞爾曲線,常用到的可分為如下幾類,1階曲線,2階曲線(二次函數算是一種),3階曲線,高階曲線。
通用的方程為
這是由p0~pn這n+1個點組成的高階方程。
但是光看這個方程的話或許大家會覺得不太理解,這東西到底能做什么?
我先逐漸的從1階曲線講起吧:
這里借鑒下這篇文章的幾幅圖片來描繪一下下列幾個情況:
1階曲線,是由兩個端點組成,無控制點,此時貝塞爾曲線的起點就從端點開始出發,走到另一個端點,而此區間沒有控制點,所以描繪出來的是一條直線。
2階曲線,則是由兩個端點加上一個控制點組成,此時,將兩個端點分別與控制點連線所產生的就有兩條線段,而分別從兩條線段上的任意兩點又能構成一條新的直線,不過此時我們不會取任意兩點,在上圖中是p0-p1形成的折線以及p1-p2形成的折線,如此一來,由p0-p1上的點以及p1-p2上的點同時出發的話這兩條線段上的點會同時動,由這兩個動點所產生的直線是一條會變化的直線,而這條直線也正是貝塞爾曲線的點在描繪貝塞爾曲線的時候所要經過的點。正因為直線式不斷變化的,所以它描繪出來的線就變成了一條平滑的曲線。
3階曲線以及高階曲線,同2階曲線一樣,2個或2個以上的控制點所構成的所有折線段的點分別出發,然后在將這些動點所形成的直線再分解成n-1個動的折線,再將折線上的點再重新鏈接,如此遞歸,最終轉換成1階,如此一來可描繪出n階貝塞爾曲線。
好了這里把大家給說暈了,先來看看實際效果吧
這是我最近做的一個開源,是仿照美團外賣來做的一個下拉動畫,可以看到這個粘性動畫就是當我們滑動tableview從而產生的一個動畫,這里我談一談我的實現思路吧,你所看到的這個粘性紅色視圖其實是用貝塞爾曲線描繪出來的閉合圖形,我們可以很直觀的可以看出它其實是一個二階貝塞爾曲線,而且控制點為整個屏幕的中心,通過獲取scrollview的滑動偏移量來繪制控制點的坐標。
下面來看一下代碼:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y+64;
refreshHeadView.offsetY = offsetY;
//異步執行,setNeedsDisplay會調用自動調用drawRect方法
[refreshHeadView setNeedsDisplay];
}
我們通過scrollview的代理方法獲取到偏移量存了起來,然后在UIView中進行繪制,setNeedsDisplay這個方法會使得UIView重繪,
#pragma mark 畫圖
- (void)drawRect:(CGRect)rect {
// 創建一個貝塞爾曲線句柄
UIBezierPath *path = [UIBezierPath bezierPath];
// 初始化該path到一個初始點
[path moveToPoint:CGPointMake(0, 0)];
// // 添加一條直線
// [path addLineToPoint:CGPointMake(0, 0)];
// 畫二元曲線,一般和moveToPoint配合使用
[path addQuadCurveToPoint:CGPointMake(self.frame.size.width, 0) controlPoint:CGPointMake(self.frame.size.width/2,- _offsetY*1.2)];
// 關閉該path
[path closePath];
// 創建描邊(Quartz)上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 將此path添加到Quartz上下文中
CGContextAddPath(context, path.CGPath);
// 設置本身顏色
[[UIColor redColor] set];
// 設置填充的路徑
CGContextFillPath(context);
}
這樣當我滑動的時候,控制點的坐標也在改變,且在屏幕中心向下移動,就構成了我們熟知的二次曲線。下面附上GitHub地址