iOS Animation: 玩轉(zhuǎn)貝塞爾曲線(xiàn)之KYAnimatePageControl

讀書(shū)筆記

先看效果

2017-08-17 18_31_25.gif

源碼鏈接:https://github.com/LeeLom/AnimationSample

這節(jié)內(nèi)容主要是利用貝塞爾曲線(xiàn)來(lái)模擬一個(gè)球產(chǎn)生形變的過(guò)程掸鹅。利用四條曲線(xiàn)來(lái)拼接出完整的球體古掏。


圖1.png

所以秸应,我們畫(huà)出這個(gè)球體的步驟瀑焦,實(shí)際上也就是確定多邊形Ac1c2Bc3c4Cc5c6Dc7c8的過(guò)程荆针,也即是確定各個(gè)點(diǎn)坐標(biāo)的過(guò)程敞嗡。我們得到這個(gè)多邊形后,利用貝塞爾曲線(xiàn)去逼近航背,既可以得到我們所需要的形變的圖像喉悴。

書(shū)中給出的確定多邊形的方法如下:

  • 確定外接正方形的位置:得到(origin_x, origin_y)
  • 確定多邊形各個(gè)坐標(biāo)的:
    • 確定多邊形的坐標(biāo)的過(guò)程中,我們需要根據(jù)每次滑動(dòng)的值玖媚,來(lái)確定offsetmovedDistance箕肃。這兩個(gè)的計(jì)算公式可以參考文中的表達(dá)式。
    CGFloat offset = _outsideRect.size.width / 3.6;
    CGFloat movedDistance = (_outsideRect.size.width * 1 / 6) * fabs(_progress - 0.5) * 2;
  • 確定各個(gè)點(diǎn)的坐標(biāo):
    • A點(diǎn):橫坐標(biāo)永遠(yuǎn)與外接多邊形相同今魔,縱坐標(biāo)為正方形的縱坐標(biāo)加上移動(dòng)的距離
    • B點(diǎn):縱坐標(biāo)和外接多邊形相同勺像,橫坐標(biāo)通過(guò)判斷左右移動(dòng)確定。像左邊移動(dòng)涡贱,則為外接多邊形的橫坐標(biāo)與正方形邊長(zhǎng)一半咏删,移動(dòng)距離的兩倍求和的值;像右邊移動(dòng)问词,則為外接多邊形的橫坐標(biāo)與正方形邊長(zhǎng)一半的和督函。

其余點(diǎn)類(lèi)似,這里不做過(guò)多解釋激挪。如果不太理解辰狡,其實(shí)可以講progress分別設(shè)置成為不同的值進(jìn)行查看即可。

  • 接著我們首先通過(guò) (origin_x, orgin_y)畫(huà)出外接正方形垄分。 邊長(zhǎng)設(shè)置為定值
  • 使用Ac1c2Bc3c4Cc5c6Dc7c8畫(huà)出外接多邊形宛篇,同時(shí)利用貝塞爾曲線(xiàn)去逼近這個(gè)多邊形
  • 書(shū)中為了方便我們便捷,還將這12個(gè)點(diǎn)分別也畫(huà)了出來(lái)薄湿。

以上叫倍,就是書(shū)中本節(jié)的內(nèi)容,最本質(zhì)的就是不斷的根據(jù)滑動(dòng)條的值去更新正方形的位置豺瘤,從而調(diào)整外接多邊形的形狀吆倦,進(jìn)而得到模擬出的貝塞爾曲線(xiàn)。


補(bǔ)充知識(shí)點(diǎn)

關(guān)于這節(jié)內(nèi)容坐求,在代碼實(shí)現(xiàn)的過(guò)程中蚕泽,發(fā)現(xiàn)了不少知識(shí)盲區(qū),網(wǎng)上查找了不少資料進(jìn)行了一個(gè)整理:

關(guān)于initWithFrameinitWithCoder的區(qū)別

  • CircleView.m 中桥嗤,初始化方法使用的是initWithFrame:须妻,那么initWithCoder與它有什么區(qū)別仔蝌?
    initWithFrame適用于代碼創(chuàng)建頁(yè)面的時(shí)候使用;
    initWithCoder適用于xib、storyboard創(chuàng)建的時(shí)候使用荒吏。與initWithCoder類(lèi)似的還有一個(gè)是awakeFromNib, 該方法在initWithCoder:方法后調(diào)用敛惊,順序是initWithCoder: --> awakeFromNib
    PS1. OC類(lèi)的初始化方法
    • 普通類(lèi)初始化:init,initialize
    • 控制器類(lèi)的初始化方法:init司倚, initialize豆混,initWithCoder:
    • UI空間類(lèi)的初始化方法:init,initialize动知, initWithFrame: 皿伺,initWithCoder:

PS2. Stack Overflow上看到一個(gè)比較有意思的問(wèn)題,跟Runloop結(jié)合的盒粮。
ViewController.m

@implementation TestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    View1 *view1 = [[View1 alloc] init];
    [self.view addSubview:view1];
}
@end

View1.m

@implementation View1

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        NSLog(@"initWithFrame");
    }
    return self;
}

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"init");
    }
    return self;
}

@end

控制臺(tái)的輸出結(jié)果如下:

2013-10-17 12:33:46.209 test1[8422:60b] initWithFrame
2013-10-17 12:33:46.211 test1[8422:60b] init

分析一下控制臺(tái)出現(xiàn)的原因:

  - [view1(View1) init] 

      - [view1(UIView) init] (called by [super init] inside View1)

        - [view1(View1) initWithFrame:CGRectZero] (called inside [view(UIView) init] )

           - [view1(UIView) initWithFrame:CGRectZero] (called by [super initWithFrame] inside View1) 
              - ...

           - NSLog(@"initWithFrame"); (prints "test1[8422:60b] initWithFrame")

      - NSLog(@"init"); (called inside [view1(View1) init] ; prints "test1[8422:60b] init")

關(guān)于UIViewCALayer的區(qū)別

  • UIView可以響應(yīng)事件鸵鸥,CALayer不可以。UIKit使用UIResponder作為響應(yīng)對(duì)象丹皱,來(lái)響應(yīng)系統(tǒng)傳遞過(guò)來(lái)的事件進(jìn)行處理妒穴,UIView作為UIResponder的響應(yīng)對(duì)象,因此可以處理摊崭。
    處理事件的函數(shù)讼油。
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
  • 每個(gè)UIView內(nèi)部都有一個(gè)CALayer在背后提供內(nèi)容的繪制和顯示,并且UIView的尺寸樣式都是由內(nèi)部的Layer提供呢簸。兩者都有樹(shù)狀層級(jí)結(jié)構(gòu)矮台,layer內(nèi)部有subLayers, view內(nèi)部有subViews。
  • View在顯示的時(shí)候根时, UIView作為layer的CALayerDelegate瘦赫,View的顯示內(nèi)容由內(nèi)部的CALayer的display
  • CALayer是默認(rèn)修改屬性支持隱式動(dòng)畫(huà),在給UIView的Layer做動(dòng)畫(huà)的時(shí)候蛤迎,View作為L(zhǎng)ayer的代理确虱,Layer通過(guò)actionForLayer:forKey:向View請(qǐng)求響應(yīng)的action(動(dòng)畫(huà)行為)
  • layer 內(nèi)部維護(hù)著三分 layer tree,分別是 presentLayer Tree(動(dòng)畫(huà)樹(shù)),modeLayer Tree(模型樹(shù)), Render Tree (渲染樹(shù)),在做 iOS動(dòng)畫(huà)的時(shí)候,我們修改動(dòng)畫(huà)的屬性替裆,在動(dòng)畫(huà)的其實(shí)是 Layer 的 presentLayer的屬性值,而最終展示在界面上的其實(shí)是提供 View的modelLayer

關(guān)于繪圖的一些函數(shù)

  • 繪制路徑的相關(guān)函數(shù)
    繪制路徑:制定起始點(diǎn)到另一個(gè)點(diǎn)校辩,然后兩個(gè)點(diǎn)之間可以使用直線(xiàn)或者曲線(xiàn)來(lái)連接,就形成了一條路徑辆童,例如使用下面的函來(lái)實(shí)現(xiàn)
    CGContextMoveToPoint()//指定起始點(diǎn)或者移動(dòng)到新的點(diǎn)    
    CGContextAddLineToPoint()//從當(dāng)前的點(diǎn)到制定的點(diǎn)之間畫(huà)一條線(xiàn)
    CGContextAddArc()//圓弧
    CGContextAddArcToPoint()//會(huì)在當(dāng)前點(diǎn)和指定點(diǎn)與坐標(biāo)系平行的直線(xiàn)做切線(xiàn)畫(huà)圓弧
    CGContextAddCurveToPoint()//畫(huà)曲線(xiàn)
    CGContextClosePath()//將起始點(diǎn)和結(jié)束點(diǎn)連接起來(lái)形成封閉的路徑
    CGContextAddEllipseInRect()//畫(huà)橢圓
    
  • 設(shè)置路徑的相關(guān)屬性
    設(shè)置需要繪制的路徑的屬性召川。設(shè)置顏色、透明度胸遇、寬度、繪制模式...例如用下面的函數(shù)來(lái)實(shí)現(xiàn)
    CGContextSetLineWidth()//線(xiàn)寬度
    CGContextSetLineJoin()//線(xiàn)連接點(diǎn)的樣式
    CGContextSetLineCap()//端點(diǎn)的樣式
    CGContextSetLineDash()//虛線(xiàn)
    CGContextSetStrokeColorWithColor()//stroke模式時(shí)的顏色
    CGContextSetFillColorWithColor()//fill模式時(shí)的顏色
    
  • 繪制內(nèi)容的兩種方式 fillStroke
    stroke: 描邊汉形,只繪制路徑
    fill:繪制路徑包括的所有區(qū)域(所有路徑都會(huì)被當(dāng)做closePath處理)
    fill的兩種模式:
    (1)non zero widing number(默認(rèn)):如果兩個(gè)路徑有重疊的時(shí)候纸镊,繪制方向相同的話(huà)倍阐,那么重疊部分的繪制可能不是我們希望的
    (2)even-odd:不受繪制方向的影響
    (3)CGContextEOFillPath
    (4)CGContextFillPath
    (5)CGContextFillRect
    (6)CGContextFillRexts
    (7)CGContextFillEllipseInRect
    CGContextStrokePath(context);
    CGContextFillPath(context);
    
  • 兩個(gè)小例子
/**
 * 示例:stroke模式繪制線(xiàn)
 */
override func draw(rect: CGRext) {
      //獲取上下文
      let context = UIGraphicsGetCurrentContext();
      //設(shè)置stroke模式的顏色使用CGColor(這里涉及顏色和顏色空間的概念)
      let strokeColor = UIColor.blueColor();
      CGContextSetStrokeColorWIthColor(context, strokeColor.CGColor);
      //設(shè)置線(xiàn)的寬度
      CGContextSetLineWidth(context, 5.0);
      //設(shè)置連接處樣式
      CGContextSetLineJoin(context, CGLineJoin.Round);
      //起始點(diǎn)
      CGContextMoveToPoint(context, 10.0, 10.0);
      //在兩個(gè)點(diǎn)之間畫(huà)一條線(xiàn),所以當(dāng)前的結(jié)束點(diǎn)成為了下一個(gè)的起始點(diǎn)
      CGContextAddLineToPoint(context, 10.0, 80.0);
      //繼續(xù)在兩個(gè)點(diǎn)之間畫(huà)一條線(xiàn)
      CGContextAddLineToPoint(context, 80.0, 80.0);
      //設(shè)置為封閉路徑逗威,將收尾連接起來(lái)
      CGContextClosePath(context);
      //繪制當(dāng)前路徑
      CGContextStrokePath(context);
}
/**
 * 示例:fill模式繪制線(xiàn)
 */
override func draw(rect: CGRext) {
      //獲取上下文
      let context = UIGraphicsGetCurrentContext();
      //設(shè)置stroke模式的顏色使用CGColor(這里涉及顏色和顏色空間的概念)
      let fillColor = UIColor.blueColor();
      CGContextSetFillColorWIthColor(context, fillColor.CGColor);
      //設(shè)置線(xiàn)的寬度
      CGContextSetLineWidth(context, 5.0);
      //設(shè)置連接處樣式
      CGContextSetLineJoin(context, CGLineJoin.Round);
      //起始點(diǎn)
      CGContextMoveToPoint(context, 10.0, 10.0);
      //在兩個(gè)點(diǎn)之間畫(huà)一條線(xiàn)峰搪,所以當(dāng)前的結(jié)束點(diǎn)成為了下一個(gè)的起始點(diǎn)
      CGContextAddLineToPoint(context, 10.0, 80.0);
      //繼續(xù)在兩個(gè)點(diǎn)之間畫(huà)一條線(xiàn)
      CGContextAddLineToPoint(context, 80.0, 80.0);
      // 設(shè)置為封閉路徑,將收尾連接起來(lái)
      // CGContextClosePath(context);
      //繪制當(dāng)前路徑
      CGContextFillPath(context);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凯旭,一起剝皮案震驚了整個(gè)濱河市概耻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罐呼,老刑警劉巖鞠柄,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嫉柴,居然都是意外死亡厌杜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)计螺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)夯尽,“玉大人,你說(shuō)我怎么就攤上這事登馒〕孜眨” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵陈轿,是天一觀(guān)的道長(zhǎng)圈纺。 經(jīng)常有香客問(wèn)我,道長(zhǎng)济欢,這世上最難降的妖魔是什么赠堵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮法褥,結(jié)果婚禮上茫叭,老公的妹妹穿的比我還像新娘。我一直安慰自己半等,他們只是感情好揍愁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著杀饵,像睡著了一般莽囤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上切距,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天朽缎,我揣著相機(jī)與錄音,去河邊找鬼。 笑死话肖,一個(gè)胖子當(dāng)著我的面吹牛北秽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播最筒,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼贺氓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了床蜘?” 一聲冷哼從身側(cè)響起辙培,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎邢锯,沒(méi)想到半個(gè)月后扬蕊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贩绕,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呀闻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熬粗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸥鹉。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛮穿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毁渗,到底是詐尸還是另有隱情践磅,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布灸异,位于F島的核電站府适,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肺樟。R本人自食惡果不足惜檐春,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望么伯。 院中可真熱鬧疟暖,春花似錦、人聲如沸田柔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)硬爆。三九已至欣舵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缀磕,已是汗流浹背缘圈。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工劣光, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糟把。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓赎线,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親糊饱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:http://www.reibang.com/p/32fcadd12108 每個(gè)UIView有一個(gè)伙伴稱(chēng)為l...
    F麥子閱讀 6,200評(píng)論 0 13
  • 前言:關(guān)于貝塞爾曲線(xiàn)與CAShapeLayer的學(xué)習(xí) 學(xué)習(xí)Demo演示: 貝塞爾曲線(xiàn)簡(jiǎn)單了解 使用UIBezier...
    麥穗0615閱讀 17,870評(píng)論 18 149
  • 每個(gè)UIView有一個(gè)伙伴稱(chēng)為layer颠黎,一個(gè)CALayer另锋。UIView實(shí)際上并沒(méi)有把自己畫(huà)到屏幕上;它繪制本身...
    shenzhenboy閱讀 3,107評(píng)論 0 17
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜狭归,今天將帶大家一窺ios動(dòng)畫(huà)全貌夭坪。在這里你可以看...
    每天刷兩次牙閱讀 8,489評(píng)論 6 30
  • 前言 本文只要描述了iOS中的Core Animation(核心動(dòng)畫(huà):隱式動(dòng)畫(huà)、顯示動(dòng)畫(huà))过椎、貝塞爾曲線(xiàn)室梅、UIVie...
    GitHubPorter閱讀 3,626評(píng)論 7 11