系列文章:
- 老司機(jī)帶你走進(jìn)Core Animation 之CAAnimation
- 老司機(jī)帶你走進(jìn)Core Animation 之CADisplayLink
- 老司機(jī)帶你走進(jìn)Core Animation 之幾種動(dòng)畫的簡單應(yīng)用
- 老司機(jī)帶你走進(jìn)Core Animation 之CAShapeLayer和CATextLayer
- 老司機(jī)帶你走進(jìn)Core Animation 之圖層的透視费彼、漸變及復(fù)制
- 老司機(jī)帶你走進(jìn)Core Animation 之粒子發(fā)射雇卷、TileLayer與異步繪制
吶,老司機(jī)之前說過會(huì)來講CALayer的小染,當(dāng)然不會(huì)食言啦,今天就講一些CALayer相關(guān)的吧调榄。
由于老司機(jī)這個(gè)想起來啥說啥的特點(diǎn)每庆,CALayer與UIView的一些關(guān)系以及CALayer的一些重要屬性缤灵,早在老司機(jī)CoreAnimation系列第一章里面就已經(jīng)做了很系統(tǒng)的介紹腮出。本著從來不湊字的原則(嘖嘖嘖利诺,違心),沒看到的同學(xué)去這里補(bǔ)票吧立倍。
不要怪老司機(jī)做事沒有條理哦口注,畢竟當(dāng)時(shí)也沒想做成系列的寝志,真的是有這么多讀者才支持我一步一步寫到這里材部。
廢話有點(diǎn)多乐导,那今天要講什么呢旺拉?就講講CALayer的兩個(gè)子類棵磷,CAShapeLayer
和CATextLayer
吧沉桌。
CAShapeLayer
其實(shí)在日常使用中规丽,CALayer能滿足需求的情況還是比較少的蒲牧,(當(dāng)然你用它來劃線還是很好用的)撇贺,原因就在于CALayer并不能很方便
的生成除了矩形的其他形狀
赌莺。(其實(shí)老司機(jī)更愿意認(rèn)為他是作為基類存在的,為所有子類提供公有屬性及方法)由于作為基類的CALayer老司機(jī)已經(jīng)介紹過了松嘶,所以接下來的兩個(gè)子類老司機(jī)都會(huì)只講述其差異性
艘狭。然而CAShapeLayer則
是作為一個(gè)強(qiáng)大無比的子類出現(xiàn)的,通過名字我們大概就可以猜到翠订,他可以畫出各樣的形狀
巢音。
- CAShapeLayer的優(yōu)勢(shì)
老生常談了,肯定是性能啊(不提性能要如何裝作一副很厲害的樣子)傲绣,他的渲染都在GPU里面
菠净,不!占!內(nèi)战坤!存!
- CAShapeLayer如何繪制出各種圖形?
我們可以從頭文件中觀察到,CAShapeLayer有一個(gè)獨(dú)有的屬性,是Path
。他是一個(gè)CGPathRef對(duì)象啊易。我們知道捆愁,這就是個(gè)路徑矾克,沒錯(cuò),CAShapeLayer就是根據(jù)這個(gè)路徑繪制出各種形狀的圖形的
。
CAShapeLayer * circle = [CAShapeLayer layer];
circle.bounds = CGRectMake(0, 0, 100, 100);
circle.position = self.view.center;
[self.view.layer addSublayer:circle];
circle.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)].CGPath;
circle.strokeColor = [UIColor redColor].CGColor;
circle.fillColor = [UIColor yellowColor].CGColor;
circle.lineWidth = 10;
circle.lineCap = @"round";
circle.strokeEnd = 0.75;
代碼很簡單,結(jié)合這張圖片你就應(yīng)該大概知道每個(gè)屬性是做什么的邦蜜。
挑幾個(gè)講一下吧:
1.path
可以看到絮供,老司機(jī)這里用的是UIBezierPath生成一個(gè)path睡榆,然后取他的CGPath來獲取路徑的包雀。他是什么呢赞草?是一層對(duì)CGPath的封裝
沾凄,他更符合OC面向?qū)ο蟮恼Z法風(fēng)格。這都不是重點(diǎn)涤垫,老司機(jī)并不想講怎么使用UIBezierPath衡楞。重點(diǎn)是
這里有一個(gè)初學(xué)者經(jīng)常會(huì)犯的錯(cuò)誤
迷守,同學(xué)們?cè)诶L制曲線的時(shí)候經(jīng)常會(huì)以layer在父圖層中的相對(duì)位置去繪制曲線礼华,這是錯(cuò)的0缃场!末盔!應(yīng)該以layer自身的坐標(biāo)系劃線蛮粮。
別不當(dāng)回事,你錯(cuò)的時(shí)候就知道咋回事了??
另外晴竞,如下圖所示,整個(gè)圓形
UIBezierPath其實(shí)是分為多個(gè)子路徑
繪制的艾扮,這個(gè)特性在CAKeyframeAnimation中會(huì)有特殊的應(yīng)用(可以回顧一下第一篇)抛虫。
2.strokeEnd
是輪廓終點(diǎn)的屬性笛洛,取值范圍[0,1]
枫吧。代表輪廓終點(diǎn)在整條路徑的百分比處,相應(yīng)的還有strokeStart屬性吴侦。
不過你應(yīng)該思考的是:
首先易阳,哪個(gè)是所謂的終點(diǎn)
?老司機(jī)可以告訴你答案法挨,靠上的那個(gè)點(diǎn)
是終點(diǎn)。那為什么0.75是在那個(gè)位置呢答渔?請(qǐng)記住冲呢,在iOS中,以x軸正方向(即水平向右)為0度,順時(shí)針旋轉(zhuǎn)一周為360度虱岂。
其實(shí)說到這里CAShapeLayer的基本用法就結(jié)束了烫饼。
- 你這么說银亲,意思是還有特殊用法咯院喜?
說不上特殊用法杠河,是兩個(gè)比較實(shí)用
但又偏門的點(diǎn)
咱士。
1.繪制空心圖層
大家看看上面這個(gè)簡單的效果,看上去還可以是吧射富。
這個(gè)跟第三篇里面那個(gè)系統(tǒng)更新樣式采用的是兩種畫法,這個(gè)沒有使用CADisplayLink做重繪叹誉。因?yàn)閷戇@個(gè)demo時(shí)沒有考慮到做暫停匠襟。
那這個(gè)怎么做呢?
把它分成兩部分吧,一部分外面不變那部分斥难,一部分中間變那部分。
這時(shí)候我們就要考慮如何畫出一個(gè)空心的圖層
担猛。
老司機(jī)先放一下空心圖層的代碼
CGRect rect = CGRectMake(0, 0, 100, 100);
UIBezierPath * rectP = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5];
UIBezierPath * circleP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 80, 80)];
[rectP appendPath:circleP];
CAShapeLayer * layer = [CAShapeLayer layer];
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.position = self.view.center;
layer.path = rectP.CGPath;
layer.fillColor = [UIColor colorWithWhite:0 alpha:0.5].CGColor;
layer.fillRule = kCAFillRuleEvenOdd;
[self.view.layer addSublayer:layer];
可以看到,事實(shí)上老司機(jī)疊加了兩條路徑
点晴,一個(gè)圓角矩形一個(gè)圓形感凤,然而這還并不夠,因?yàn)?code>layer還要知道自己的填充判斷規(guī)則
粒督,就是重要的fillRule
屬性陪竿。
這個(gè)屬性是用來判斷某一點(diǎn)是否在填充區(qū)域內(nèi)的判斷規(guī)則。
他有兩個(gè)枚舉值屠橄,kCAFillRuleNonZero
和kCAFillRuleEvenOdd
族跛。
這里介紹一下分別是如何判斷的
kCAFillRuleNonZero
從該點(diǎn)向任意方向畫一條射線,若順時(shí)針穿過該射線的條數(shù)與逆時(shí)針穿過該射線的條數(shù)不相等锐墙,則表示該點(diǎn)在區(qū)域內(nèi)部礁哄,否則在外部。kCAFillRuleEvenOdd
從該點(diǎn)向任意方向畫一條射線溪北,如果該射線穿過奇數(shù)條路徑則該點(diǎn)在區(qū)域內(nèi)部桐绒,否則在外部。
2.strokeEnd
為什么又說strokeEnd之拨?你還說你不是湊字茉继!
真不是,這次說他主要是想表達(dá)這個(gè)屬性是默認(rèn)支持隱式動(dòng)畫的
蚀乔。
隱式動(dòng)畫就是不用顯示聲明烁竭,系統(tǒng)默認(rèn)為我們實(shí)現(xiàn)的動(dòng)畫。
網(wǎng)上99%的CAShapeLayer教程都是用這個(gè)屬性做一個(gè)環(huán)形指示器吉挣,誒派撕,老司機(jī)就是不講這個(gè)例子
婉弹,你們自己去想吧,無辜臉腥刹。
像下面這個(gè)圖一樣马胧,不過他們都留了一個(gè)坑沒說汉买。我敢保證如果你只用strokeEnd和strokeStart兩個(gè)屬性交替配合衔峰,絕對(duì)實(shí)現(xiàn)不了這個(gè)效果。如果不信邪你可以現(xiàn)在去試試
蛙粘,嘖嘖嘖垫卤。我會(huì)在文章的最后放出如何才能解決你們遇到的問題,別著急往下拉哦出牧。(你要是沒遇到問題穴肘,老司機(jī)再教你一個(gè)快捷鍵,command + A
舔痕,然后按delete鍵
可以快速整理代碼)评抚。
恩,這個(gè)strokeEnd的隱式動(dòng)畫講完伯复,上面老司機(jī)放的那個(gè)綠色背景進(jìn)度圖那個(gè)你也能做了慨代,當(dāng)給你們留的作業(yè)了自己去實(shí)現(xiàn)吧??。
3.虛線
這個(gè)屬性真的是一直被忽略
啸如,從未被使用侍匙。
代碼還是上面circle那段代碼,在末尾添了三句話
circle.lineWidth = 2;
circle.lineDashPhase = 3;
circle.lineDashPattern = @[@5,@5,@15,@5];
因?yàn)殚g距很小叮雳,原來的線寬顯示不出來所以這里更改了線寬想暗。
先看lineDashPattern這個(gè)屬性。這個(gè)屬性指的是實(shí)線與虛線長度交替的數(shù)組帘不。注意奇數(shù)位為實(shí)線
说莫,偶數(shù)位為虛線
,單位像素
寞焙。系統(tǒng)會(huì)按照給定數(shù)組自動(dòng)重復(fù)設(shè)置虛線储狭。
lineDashPhase這個(gè)屬性是告訴系統(tǒng)從多少開始計(jì)算這個(gè)距離。比如上圖中第一段實(shí)現(xiàn)的距離明顯小于5棺弊,其實(shí)他是2晶密,因?yàn)槲覀儚?開始計(jì)算,5 - 3就剩2了模她。
說到這里稻艰,CAShapeLayer的一些用法就真的介紹完畢了。
CATextLayer
相比CAShapeLayer侈净,可能CATextLayer的用途更加單一一些尊勿,他可以用來展示文字
僧凤。
那個(gè),等會(huì)再關(guān)瀏覽器元扔,你先聽我說完??
我知道躯保,有UILabel,你完全不需要使用這個(gè)澎语。
但是存在必定是有他的意義的途事。正如UILabel是已經(jīng)封裝完成的,有一些我們想用的功能UILabel不一定有擅羞,比如下面這個(gè):
當(dāng)然這個(gè)效果用兩個(gè)label疊加再用一個(gè)mask也可以實(shí)現(xiàn)尸变,不過兩個(gè)label實(shí)在是不優(yōu)雅
。所以老司機(jī)決定用CATextLayer來實(shí)現(xiàn)這個(gè)效果
减俏。
先來講一下CATextLayer的基本使用方法吧召烂。
他的幾個(gè)屬性都是見名知意,就是跟label相差無幾的屬性娃承。最簡單的你想讓他顯示文字的話直接給string屬性賦值就好了奏夫。
不要太簡單,哈哈哈??
CATextLayer我們就講到這里历筝。
怎么可能酗昼,我當(dāng)然會(huì)把這個(gè)的實(shí)現(xiàn)方式告訴大家啊~
先給大家看一個(gè)效果:
這個(gè)效果你一定會(huì)吧,一個(gè)綠色的CALayer漫谷,仔雷,上面蓋了一個(gè)紅色的CAShapeLayer,strokeEnd從0到1舔示,對(duì)吧碟婆。
那怎么讓他只顯示字的區(qū)域呢
?記得老司機(jī)曾經(jīng)講個(gè)CALayer的一個(gè)屬性叫做mask屬性
么惕稻?對(duì)咯竖共,就是以一個(gè)CATextLayer做紅色的CALayer的mask,CATextLayer的字體設(shè)置有顏色俺祠,背景設(shè)置透明色公给,這樣就只能顯示出紅色的CALayer的文字部分了
把他封裝在一個(gè)UIView里面我們的展示歌詞的Label就完成了。大家可以去[這里下載這個(gè)Demo](https://github.com/CodeWicky/DWLyricLabel.git)哦
恩蜘渣,其實(shí)只要是顯示文字淌铐,CATextLayer都可以完成,想要定制一些UILabel沒有的功能蔫缸,都可以考慮使用CATextLayer腿准。
CATextLayer也算是講完了~
回過頭來說之前留的那個(gè)坑。問題就是當(dāng)你第一循環(huán)結(jié)束
后你想把你的strokeEnd恢復(fù)成0
你卻發(fā)現(xiàn)他是以動(dòng)畫形式恢復(fù)
回去的不是你要的效果對(duì)吧拾碌?這就是因?yàn)樗碾[式動(dòng)畫了吐葱。因?yàn)檫@時(shí)候我們不需要他的動(dòng)畫是吧街望?知道原因就好辦了,我們可以通過
CATransaction顯式的關(guān)閉他的動(dòng)畫弟跑,恢復(fù)成0灾前,再打開動(dòng)畫,是不是就行了孟辑?哈哈哈哎甲,就是這么簡單。
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.layer.strokeEnd = 0;
[CATransaction setDisableActions:NO];
[CATransaction commit];
坑填完了扑浸,看截圖你們也知道老司機(jī)是熬夜給你們碼字的吧烧给,是時(shí)候點(diǎn)波贊??加波關(guān)注??了~