前言
昨天剛做完項目的新版本、除了嘗試一些新的架構之外、功能方面并沒什么特別的地方掏婶。
但是順手搞了一些還算好玩的東西、其一就是這個導航欄的動畫潭陪。
感覺還算簡單易懂雄妥、分享一下(其實更多是最近攢了好多封面、不貼出來憋得人難受)
依溯。
思路
先介紹CA的兩個方法:
- 基于原始狀態(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);
知道了這兩個方法老厌、剩下就是如何使用形變和位移以達到想要的效果了。
這里黎炉、需要分兩部分來看枝秤、一部分是位移、一部分是形變
而且慷嗜、如果將一整個動畫以及翻頁動作看成1淀弹。那么位移和形變又需要分成兩部分來看:0到0.5以及0.5到1丹壕。
其實一點都不難、畫個圖看一眼垦页。連一元方程都不算雀费、完全是小學算術題~甚至連奧數(shù)都算不上。
0到0.5區(qū)間內
-
先看形變
在0.5時痊焊、我們需要將線條長度從left_width
形變成max_width
-
再看位移
與此同時如果想讓線條在左側看起來并沒有移動盏袄、就需要將線條的x軸一點點向右移動。這個移動的值呢?
由于形變是雙向的薄啥、右側和左側都會變長辕羽。那么對于左側最終將是中間時最終形變差值
的一半。
具體到數(shù)值:
最左側到中心點時x軸的位移 = 最左側到中心點時形變的差值/2 = (max_width - left_width)/2
0.5到1區(qū)間內
-
依舊先看形變
和之前的形變相同
-
然后來看位移
同理垄惧、如果我的長度減少了X刁愿、那么我如果想保證看起來右側位置不會改變、考慮到形變是左右同時發(fā)生到逊、就需要向右移動X/2铣口。
具體到數(shù)值:
中心點到最右側時x軸的位移 = 中心點到最右時形變的差值/2 = (max_width - right_width)/2
具體函數(shù)
以我項目里兩個按鈕(self.titleBtn1
/self.titleBtn2
)為例
if (0 <= offsetRate && offsetRate <= 0.5) {
/*
* 左側與中間相互移動
*/
//x軸位移 :: 中間時位移 * 偏移比例系數(shù)
CGFloat translationOfX = _translationofX_center * offsetRate * 2;
self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0);
//x軸形變 :: 1 + (最大時相對形變) * 偏移比例系數(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) {
/*
* 中間與右側相互移動
*/
//x軸位移 :: 中間時位移 + 最終位移 * 偏移比例系數(shù)
CGFloat translationOfX = _translationofX_center + _translationofX_right * (offsetRate - 0.5) * 2;
self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0);
//x軸形變 :: 最大時形變 - (最大形變 - 最終形變) * 偏移比例系數(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;
//位于左側時寬度
CGFloat _btn1Width;
//位于右側時寬度
CGFloat _btn2Width;
//從左側移到中心時x軸位移
CGFloat _translationofX_center;
//從中心移到右側時x軸位移
//所以總位移就是_translationofX_center+_translationofX_right
CGFloat _translationofX_right;
//位于中心時形變
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);
}
將屏幕滑動的偏移量傳遞進來
#pragma mark UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetX = scrollView.contentOffset.x;
CGFloat offsetRate = offsetX/BSScreen_Width;
//將偏移率傳遞給navView
[self.navView configLingWithOffsetRate:offsetRate];
}
Demo
上面的例子的代碼其實都已經(jīng)列出來了、沒什么再單獨傳Demo的必要觉壶。
但是畢竟開了個帖子脑题、連個Demo都沒有不好看。于是上午干脆封裝了一個小工具出來铜靶。
但是只封裝了移動的動畫叔遂、并沒封裝按鈕變色等等一系列功能。
用起來也挺簡單的争剿、只要將按鈕的數(shù)組
已艰、下方橫線
交付、在屏幕滑動的時候把偏移量
傳遞進去蚕苇、就能自動工作了哩掺。寬度啊什么都會自己算:
@interface KTNavScrollTool : NSObject
/**
初始化
@param titleArr 按鈕數(shù)組
@param line 需要移動的橫線
@return 實例對象
*/
- (instancetype)initWithTitleArr:(NSArray<UIView *> *)titleArr line:(UIView *)line;
/**
移動的函數(shù)
@param offsetRate scrollview滾動式的偏移量的比例
*/
- (void)configLingWithOffsetRate:(CGFloat)offsetRate;
@end