www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]在最近做個(gè)一個(gè)自定義PageControl——KYAnimatedPageControl中,我實(shí)現(xiàn)了CALayer的形變動(dòng)畫以及CALayer的彈性動(dòng)畫,效果先過目: 先做個(gè)提綱:第一個(gè)分享的主題

在最近做個(gè)一個(gè)自定義PageControl——KYAnimatedPageControl中,我實(shí)現(xiàn)了CALayer的形變動(dòng)畫以及CALayer的彈性動(dòng)畫,效果先過目:

 

 

先做個(gè)提綱:

第一個(gè)分享的主題是“如何讓CALayer發(fā)生形變”,這個(gè)技術(shù)在我之前一個(gè)項(xiàng)目 ———— KYCuteView 中有涉及,也寫了篇簡短的實(shí)現(xiàn)原理博文。今天再舉一個(gè)例子。

之前我也做過類似果凍效果的彈性動(dòng)畫,比如這個(gè)項(xiàng)目—— KYGooeyMenu。用到的核心技術(shù)是CAKeyframeAnimation,然后設(shè)置幾個(gè)不同狀態(tài)的關(guān)鍵幀,就能初步達(dá)到這種彈性效果。但是,畢竟只有幾個(gè)關(guān)鍵幀,而且是需要手動(dòng)計(jì)算,不精確不說,動(dòng)畫也不夠細(xì)膩,畢竟你不可能手動(dòng)創(chuàng)建60個(gè)關(guān)鍵幀。所以,今天的第二個(gè)主題是 —— “如何用阻尼振動(dòng)函數(shù)創(chuàng)建出60個(gè)關(guān)鍵幀”,從而實(shí)現(xiàn)CALayer產(chǎn)生類似[UIView animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion] 的彈性動(dòng)畫。

正文。

如何讓CALayer發(fā)生形變?

關(guān)鍵技術(shù)很簡單:你需要用多條貝塞爾曲線 “拼” 出這個(gè)Layer。之所以這樣做的原因不言而喻,因?yàn)檫@樣方便我們發(fā)生形變。

比如 KYAnimatedPageControl 中的這個(gè)小球,其實(shí)它是這么被畫出來的:

 

 

小球是由弧AB、弧BC、弧CD、弧DA 四段組成,其中每段弧都綁定兩個(gè)控制點(diǎn):弧AB 綁定的是 C1 、 C2;弧BC 綁定的是 C3 、 C4 .....

如何表達(dá)各個(gè)點(diǎn)?

首先,A、B、C、D是四個(gè)動(dòng)點(diǎn),控制他們動(dòng)的變量是ScrollView的contentOffset.x。我們可以在-(void)scrollViewDidScroll:(UIScrollView *)scrollView中實(shí)時(shí)獲取這個(gè)變量,并把它轉(zhuǎn)換成一個(gè)控制在 0~1 的系數(shù),取名為factor。

1

_factor = MIN(1, MAX(0, (ABS(scrollView.contentOffset.x - self.lastContentOffset) / scrollView.frame.size.width)));

假設(shè)A、B、C、D的最大變化距離為小球直徑的2/5。那么結(jié)合這個(gè)0~1的系數(shù),我們可以得出A、B、C、D的真實(shí)變化距離 extra 為:extra = (self.width * 2 / 5) * factor。當(dāng)factor == 1時(shí),達(dá)到最大形變狀態(tài),此時(shí)四個(gè)點(diǎn)的變化距離均為(self.width * 2 / 5)。

注意:根據(jù)滑動(dòng)方向,我們還要根據(jù)是B點(diǎn)移動(dòng)還是D點(diǎn)移動(dòng)。

CGPoint pointA = CGPointMake(rectCenter.x ,self.currentRect.origin.y + extra); CGPoint pointB = CGPointMake(self.scrollDirection == ScrollDirectionLeft ? rectCenter.x + self.currentRect.size.width/2 : rectCenter.x + self.currentRect.size.width/2 + extra*2 ,rectCenter.y); CGPoint pointC = CGPointMake(rectCenter.x ,rectCenter.y + self.currentRect.size.height/2 - extra); CGPoint pointD = CGPointMake(self.scrollDirection == ScrollDirectionLeft ? self.currentRect.origin.x - extra*2 : self.currentRect.origin.x, rectCenter.y);

然后是控制點(diǎn):

關(guān)鍵是要知道上圖中A-C1 、B-C2、B-C3、C-C4....這些水平和垂直虛線的長度,命名為offSet。經(jīng)過多次嘗試,我得出的結(jié)論是:

當(dāng)offSet設(shè)置為 直徑除以3.6 的時(shí)候,弧線能完美地貼合成圓弧。我隱約感覺這個(gè) 3.6 是必然,貌似和360度有某種關(guān)系,或許通過演算能得出 3.6 這個(gè)值的必然性,但我沒有嘗試。

因此,各個(gè)控制點(diǎn)的坐標(biāo):

CGPoint c1 = CGPointMake(pointA.x + offset, pointA.y); CGPoint c2 = CGPointMake(pointB.x, pointB.y - offset); CGPoint c3 = CGPointMake(pointB.x, pointB.y + offset); CGPoint c4 = CGPointMake(pointC.x + offset, pointC.y); CGPoint c5 = CGPointMake(pointC.x - offset, pointC.y); CGPoint c6 = CGPointMake(pointD.x, pointD.y + offset); CGPoint c7 = CGPointMake(pointD.x, pointD.y - offset); CGPoint c8 = CGPointMake(pointA.x - offset, pointA.y);

有了終點(diǎn)和控制點(diǎn),就可以用UIBezierPath 中提供的方法 - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2; 畫線段了。

重載CALayer的- (void)drawInContext:(CGContextRef)ctx;方法,在里面畫圖案:

- (void)drawInContext:(CGContextRef)ctx{ ....//在這里計(jì)算每個(gè)點(diǎn)的坐標(biāo) UIBezierPath* ovalPath = [UIBezierPath bezierPath]; [ovalPath moveToPoint: pointA]; [ovalPath addCurveToPoint:pointB controlPoint1:c1 controlPoint2:c2]; [ovalPath addCurveToPoint:pointC controlPoint1:c3 controlPoint2:c4]; [ovalPath addCurveToPoint:pointD controlPoint1:c5 controlPoint2:c6]; [ovalPath addCurveToPoint:pointA controlPoint1:c7 controlPoint2:c8]; [ovalPath closePath]; CGContextAddPath(ctx, ovalPath.CGPath); CGContextSetFillColorWithColor(ctx, self.indicatorColor.CGColor); CGContextFillPath(ctx); }

現(xiàn)在,當(dāng)你滑動(dòng)ScrollView的時(shí)候,小球就會(huì)形變了。

如何用阻尼振動(dòng)函數(shù)創(chuàng)建出60個(gè)關(guān)鍵幀?

上面的例子中,有個(gè)很重要的因素,就是ScrollView中的contentOffset.x這個(gè)變量,沒有這個(gè)輸入,那接下來什么都不會(huì)發(fā)生。但想要獲得這個(gè)變量,是需要用戶觸摸、滑動(dòng)去交互產(chǎn)生的。在某個(gè)動(dòng)畫中用戶是沒有直接的交互輸入的,比如當(dāng)手指離開之后,要讓這個(gè)小球以果凍效果彈回初始狀態(tài),這個(gè)過程手指已經(jīng)離開屏幕,也就沒有了輸入,那么用上面的方法肯定行不通,所以,我們可以用CAAnimation.

我們知道,iOS7中蘋果在 UIView(UIViewAnimationWithBlocks) 加入了一個(gè)新的制作彈性動(dòng)畫的工廠方法:

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

但是沒有直接的關(guān)于彈性的 CAAnimation 子類,類似CABasicAnimation或CAKeyframeAnimation 來直接給CALayer添加動(dòng)畫。好消息是iOS9中添加了公開的 CASpringAnimation。但是出于兼容低版本以及對(duì)知識(shí)探求的角度,我們可以了解一下如何手動(dòng)給CALayer創(chuàng)建一個(gè)彈性動(dòng)畫。

在開始之前需要復(fù)習(xí)一下高中物理知識(shí) ———— 阻尼振動(dòng),你可以點(diǎn)擊高亮字體的鏈接稍微復(fù)習(xí)一下。

 

 

 

 

根據(jù)維基百科,我們可以得到如下振動(dòng)函數(shù)通式:

 

 

當(dāng)然這只是一個(gè)通式,我們需要讓 圖像過(0,0),并且最后衰減到1 。我們可以讓原圖像先繞X軸翻轉(zhuǎn)180度,也就是加一個(gè)負(fù)號(hào)。然后沿y軸向上平移一個(gè)單位。所以稍加變形可以得到如下函數(shù):

 

 

想看函數(shù)的圖像?沒問題,推薦一個(gè)在線查看函數(shù)圖象的網(wǎng)站 —— Desmos ,把這段公式 1-left(e^{-5x}cdot cos (30x)right) 復(fù)制粘帖進(jìn)去就可以看到圖像。

改進(jìn)后的函數(shù)圖像是這樣的:

 

 

完美滿足了我們 圖形過(0,0),震蕩衰減到1 的要求。其中式子中的 5 相當(dāng)于阻尼系數(shù),數(shù)值越小幅度越大;式子中的 30 相當(dāng)于震蕩頻率 ,數(shù)值越大震蕩次數(shù)越多。

接下來就需要轉(zhuǎn)換成代碼。

總體思路是創(chuàng)建60幀關(guān)鍵幀(因?yàn)槠聊坏淖罡咚⑿骂l率就是60FPS),然后把這60幀數(shù)據(jù)賦值給 CAKeyframeAnimation 的 values 屬性。

用以下代碼生成60幀后保存到一個(gè)數(shù)組并返回它,其中//1就是利用剛才的公式創(chuàng)建60個(gè)數(shù)值:

+(NSMutableArray *) animationValues:(id)fromValue toValue:(id)toValue usingSpringWithDamping:(CGFloat)damping initialSpringVelocity:(CGFloat)velocity duration:(CGFloat)duration{ //60個(gè)關(guān)鍵幀 NSInteger numOfPoints = duration * 60; NSMutableArray *values = [NSMutableArray arrayWithCapacity:numOfPoints]; for (NSInteger i = 0; i < numOfPoints; i++) { [values addObject:@(0.0)]; } //差值 CGFloat d_value = [toValue floatValue] - [fromValue floatValue]; for (NSInteger point = 0; point CGFloat x = (CGFloat)point / (CGFloat)numOfPoints; CGFloat value = [toValue floatValue] - d_value * (pow(M_E, -damping * x) * cos(velocity * x)); //1 y = 1-e^{-5x} * cos(30x) values[point] = @(value); } return values; }

接下來創(chuàng)建一個(gè)對(duì)外的類方法,并返回一個(gè) CAKeyframeAnimation :

+(CAKeyframeAnimation *)createSpring:(NSString *)keypath duration:(CFTimeInterval)duration usingSpringWithDamping:(CGFloat)damping initialSpringVelocity:(CGFloat)velocity fromValue:(id)fromValue toValue:(id)toValue{ CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:keypath]; NSMutableArray *values = [KYSpringLayerAnimation animationValues:fromValue toValue:toValue usingSpringWithDamping:damping * dampingFactor initialSpringVelocity:velocity * velocityFactor duration:duration]; anim.values = values; anim.duration = duration; return anim; }

另一個(gè)關(guān)鍵

以上,我們創(chuàng)建了 CAKeyframeAnimation 。但是這些values到底是對(duì)誰起作用的呢?如果你熟悉CoreAnimation的話,沒錯(cuò),是對(duì)傳入的keypath起作用。而這些keypath其實(shí)就是CALayer中的屬性@property。比如,之所以當(dāng)傳入的keypath為transform.rotation.x時(shí)CAKeyframeAnimation會(huì)讓layer發(fā)生旋轉(zhuǎn),就是因?yàn)镃AKeyframeAnimation發(fā)現(xiàn)CALayer中有這么個(gè)屬性叫transform,于是動(dòng)畫就發(fā)生了?,F(xiàn)在我們需要改變的是主題一中的那個(gè)factor變量,所以,很自然地想到,我們可以給CALayer補(bǔ)充一個(gè)屬性名為factor就行了,這樣CAKeyframeAnimation加到layer上時(shí)發(fā)現(xiàn)layer有這個(gè)factor屬性,就會(huì)把60幀不同的values賦值給factor。當(dāng)然我們要把fromValue和toValue控制在0~1:

CAKeyframeAnimation *anim = [KYSpringLayerAnimation createSpring:@"factor" duration:0.8 usingSpringWithDamping:0.5 initialSpringVelocity:3 fromValue:@(1) toValue:@(0)]; self.factor = 0; [self addAnimation:anim forKey:@"restoreAnimation"];

最后一步,雖然CAKeyframeAnimation實(shí)時(shí)地去改變了我們想要的factor,但我們還得通知屏幕刷新,這樣才能看到動(dòng)畫。

+(BOOL)needsDisplayForKey:(NSString *)key{ if ([key isEqual:@"factor"]) { return YES; } return [super needsDisplayForKey:key]; }

上面的代碼通知屏幕當(dāng)factor發(fā)生變化時(shí),實(shí)時(shí)刷新屏幕。

最后的最后,你需要重載CALayer中的-(id)initWithLayer:(GooeyCircle *)layer方法,為了保證動(dòng)畫能連貫起來,你需要拷貝前一個(gè)狀態(tài)的layer及其所有屬性。

-(id)initWithLayer:(GooeyCircle *)layer{ self = [super initWithLayer:layer]; if (self) { self.indicatorSize = layer.indicatorSize; self.indicatorColor = layer.indicatorColor; self.currentRect = layer.currentRect; self.lastContentOffset = layer.lastContentOffset; self.scrollDirection = layer.scrollDirection; self.factor = layer.factor; } return self; }

總結(jié):

做自定義的動(dòng)畫最關(guān)鍵的就是要有變量,要有輸入。像滑動(dòng)ScrollView的時(shí)候,滑動(dòng)的距離就是動(dòng)畫的輸入,可以作為動(dòng)畫的變量;當(dāng)沒有交互的時(shí)候,可以用CAAnimation。其實(shí)CAAnimation底層就有個(gè)定時(shí)器,而定時(shí)器的作用就是可以產(chǎn)生變量,時(shí)間就是變量,就可以產(chǎn)生變化的輸入,就能看到變化的狀態(tài),連起來就是動(dòng)畫了。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉