iOS仿微博導(dǎo)航欄動(dòng)畫(huà)(CoreGraphics)的實(shí)現(xiàn)方法
前言
昨天剛做完項(xiàng)目的新版本、除了嘗試一些新的架構(gòu)之外、功能方面并沒(méi)什么特別的地方。
但是順手搞了一些還算好玩的東西、其一就是這個(gè)導(dǎo)航欄的動(dòng)畫(huà)。
感覺(jué)還算簡(jiǎn)單易懂、分享一下(其實(shí)更多是最近攢了好多封面、不貼出來(lái)憋得人難受)。
導(dǎo)航欄動(dòng)畫(huà).gif
思路
先介紹CA的兩個(gè)方法:
基于原始狀態(tài)的位移
CG_EXTERN CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
基于原始狀態(tài)的形變
CG_EXTERN CGAffineTransform CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
知道了這兩個(gè)方法、剩下就是如何使用形變和位移以達(dá)到想要的效果了。
這里、需要分兩部分來(lái)看、一部分是位移、一部分是形變
而且、如果將一整個(gè)動(dòng)畫(huà)以及翻頁(yè)動(dòng)作看成1。那么位移和形變又需要分成兩部分來(lái)看:0到0.5以及0.5到1。
其實(shí)一點(diǎn)都不難、畫(huà)個(gè)圖看一眼。連一元方程都不算、完全是小學(xué)算術(shù)題~甚至連奧數(shù)都算不上。
0到0.5區(qū)間內(nèi)
先看形變
在0.5時(shí)、我們需要將線條長(zhǎng)度從left_width形變成max_width
再看位移
與此同時(shí)如果想讓線條在左側(cè)看起來(lái)并沒(méi)有移動(dòng)、就需要將線條的x軸一點(diǎn)點(diǎn)向右移動(dòng)。這個(gè)移動(dòng)的值呢?
由于形變是雙向的、右側(cè)和左側(cè)都會(huì)變長(zhǎng)。那么對(duì)于左側(cè)最終將是中間時(shí)最終形變差值的一半。
具體到數(shù)值:
最左側(cè)到中心點(diǎn)時(shí)x軸的位移 = 最左側(cè)到中心點(diǎn)時(shí)形變的差值/2 = (max_width - left_width)/2
0.5到1區(qū)間內(nèi)
依舊先看形變
和之前的形變相同
形變-0.5到1
然后來(lái)看位移
同理、如果我的長(zhǎng)度減少了X、那么我如果想保證看起來(lái)右側(cè)位置不會(huì)改變、考慮到形變是左右同時(shí)發(fā)生、就需要向右移動(dòng)X/2。
具體到數(shù)值:
中心點(diǎn)到最右側(cè)時(shí)x軸的位移 = 中心點(diǎn)到最右時(shí)形變的差值/2 = (max_width - right_width)/2
具體函數(shù)
以我項(xiàng)目里兩個(gè)按鈕(self.titleBtn1/self.titleBtn2)為例
if (0 <= offsetRate && offsetRate <= 0.5) { /* * 左側(cè)與中間相互移動(dòng) */ //x軸位移 :: 中間時(shí)位移 * 偏移比例系數(shù) CGFloat translationOfX = _translationofX_center * offsetRate * 2; self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0); //x軸形變 :: 1 + (最大時(shí)相對(duì)形變) * 偏移比例系數(shù) CGFloat flagScale = 1 + (_flagScale_center - 1) * (offsetRate * 2); self.line.transform = CGAffineTransformScale(self.line.transform, flagScale, 1); }else if (0.5 < offsetRate && offsetRate <= 1) { /* * 中間與右側(cè)相互移動(dòng) */ //x軸位移 :: 中間時(shí)位移 + 最終位移 * 偏移比例系數(shù) CGFloat translationOfX = _translationofX_center + _translationofX_right * (offsetRate - 0.5) * 2; self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0); //x軸形變 :: 最大時(shí)形變 - (最大形變 - 最終形變) * 偏移比例系數(shù) CGFloat flagScale = _flagScale_center - (_flagScale_center - _btn2Width/_btn1Width) * (offsetRate - 0.5) * 2; self.line.transform = CGAffineTransformScale(self.line.transform, flagScale, 1); }
其中的某些參數(shù)的意義以及取值:
{ //整體最大寬度 CGFloat _maxWidth; //位于左側(cè)時(shí)寬度 CGFloat _btn1Width; //位于右側(cè)時(shí)寬度 CGFloat _btn2Width; //從左側(cè)移到中心時(shí)x軸位移 CGFloat _translationofX_center; //從中心移到右側(cè)時(shí)x軸位移 //所以總位移就是_translationofX_center+_translationofX_right CGFloat _translationofX_right; //位于中心時(shí)形變 CGFloat _flagScale_center; } { _btn1Width = self.titleBtn1.width; _btn2Width = self.titleBtn2.width; _maxWidth = self.titleBtn2.right - self.titleBtn1.left; _translationofX_center = (_maxWidth - _btn1Width)/2; _translationofX_right = (_maxWidth - _btn2Width)/2; _flagScale_center = _maxWidth/_btn1Width; self.line.frame = CGRectMake(self.titleBtn1.left, self.height, self.titleBtn1.width, 1); }
將屏幕滑動(dòng)的偏移量傳遞進(jìn)來(lái)
#pragma mark UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat offsetX = scrollView.contentOffset.x; CGFloat offsetRate = offsetX/BSScreen_Width; //將偏移率傳遞給navView [self.navView configLingWithOffsetRate:offsetRate]; }
Demo
上面的例子的代碼其實(shí)都已經(jīng)列出來(lái)了、沒(méi)什么再單獨(dú)傳Demo的必要。
但是畢竟開(kāi)了個(gè)帖子、連個(gè)Demo都沒(méi)有不好看。于是上午干脆封裝了一個(gè)小工具出來(lái)。
但是只封裝了移動(dòng)的動(dòng)畫(huà)、并沒(méi)封裝按鈕變色等等一系列功能。
用起來(lái)也挺簡(jiǎn)單的、只要將按鈕的數(shù)組、下方橫線交付、在屏幕滑動(dòng)的時(shí)候把偏移量傳遞進(jìn)去、就能自動(dòng)工作了。寬度啊什么都會(huì)自己算:
@interface KTNavScrollTool : NSObject /** 初始化 @param titleArr 按鈕數(shù)組 @param line 需要移動(dòng)的橫線 @return 實(shí)例對(duì)象 */ - (instancetype)initWithTitleArr:(NSArray<UIView *> *)titleArr line:(UIView *)line; /** 移動(dòng)的函數(shù) @param offsetRate scrollview滾動(dòng)式的偏移量的比例 */ - (void)configLingWithOffsetRate:(CGFloat)offsetRate; @end
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- iOS實(shí)現(xiàn)抖音點(diǎn)贊動(dòng)畫(huà)效果
- iOS實(shí)現(xiàn)點(diǎn)贊動(dòng)畫(huà)特效
- iOS仿AirPods彈出動(dòng)畫(huà)
- iOS自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的幾種情況
- iOS自定義UIButton點(diǎn)擊動(dòng)畫(huà)特效
- iOS基于CATransition實(shí)現(xiàn)翻頁(yè)、旋轉(zhuǎn)等動(dòng)畫(huà)效果
- iOS實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的3種方法示例
- iOS實(shí)現(xiàn)數(shù)字倍數(shù)動(dòng)畫(huà)效果
- iOS如何優(yōu)雅地實(shí)現(xiàn)序列動(dòng)畫(huà)詳解
- iOS仿抖音視頻加載動(dòng)畫(huà)效果的實(shí)現(xiàn)方法
- 詳解 iOS 系統(tǒng)中的視圖動(dòng)畫(huà)
相關(guān)文章
使用設(shè)計(jì)模式中的Singleton單例模式來(lái)開(kāi)發(fā)iOS應(yīng)用程序
這篇文章主要介紹了使用設(shè)計(jì)模式中的Singleton單例模式來(lái)開(kāi)發(fā)iOS應(yīng)用程序的例子,示例代碼為傳統(tǒng)的Objective-C語(yǔ)言,需要的朋友可以參考下2016-03-03iOS利用余弦函數(shù)實(shí)現(xiàn)卡片瀏覽工具
這篇文章主要為大家詳細(xì)介紹了iOS利用余弦函數(shù)實(shí)現(xiàn)卡片瀏覽工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04iOS中UIAlertController設(shè)置自定義標(biāo)題與內(nèi)容的方法
UIAlertController是iOS8推出的新概念,取代了之前的 UIAlertView和UIActionSheet(雖然現(xiàn)在仍可以使用,但是會(huì)有警告)。下面這篇文章主要給大家介紹了關(guān)于iOS中UIAlertController如何設(shè)置自定義標(biāo)題與內(nèi)容的相關(guān)資料,需要的朋友可以參考下。2017-10-10簡(jiǎn)單說(shuō)說(shuō)iOS之WKWebView的用法小結(jié)
iOS8.0之后我們使用 WebKit框架中的WKWebView來(lái)加載網(wǎng)頁(yè)。這篇文章主要介紹了簡(jiǎn)單說(shuō)說(shuō)iOS之WKWebView的用法小結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01iOS判斷運(yùn)營(yíng)商類(lèi)型的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇iOS判斷運(yùn)營(yíng)商類(lèi)型的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04