引言:今天就花半個小時的時間,學習一下標哥的導航頭像縮放,小總結一下,若是侵了標哥的權,請見怪,及時提醒,本篇僅供學習。
就如標哥,微博所說,在很多App中,經常存在一種需求就是,界面上下滾動時用戶頭像也跟著變化,而用戶頭像是放在系統的導航條上的。也有很多人,嘗試自定義View,但是標哥,說了,沒有必要,直接用系統的便可。(雖然,我不太認識標哥,哈哈)。
- 要學到的知識點:
- 如何分析實現原理
- 如何實現縮放效果
- 如何將計算縮放系數
-
跟著效果圖一探究竟
如圖所示,要明白兩點:
一、是當往下滾動時,在一定范圍內,會放大頭像,但是不會放得過大;
二、在往上滾動時,在一定范圍內,會縮小頭像,但是不會縮小得過小:
這說明了什么呢?頭像的縮放和放大都是有上、下限的,而且,頭像的起點y值始終不變。
-
在啰嗦一下實現原理
從效果圖可以看出以下幾點:
1.向上移動頭像會縮小,但是有下限
2.向下移動頭像會放大,但是有上限
3.頭像的起點y始終不變
問題:
1.如何縮放控件--->使用transform來實現。
2.怎樣做到每次都需要更新頭像的y坐標,以保證y值不變。
3.有上限、下限,應設置,最小縮放系數及最大縮放系數。
解決:
1.要設置最小/最大縮放系數,我們就需要計算出來,但是如何計算呢?其實挺簡單的,我們只需要設置下拉或者上拉需要處理縮放的最大距離,就可以計算出來了。
計算放大系數: MIN(1.5, 1 – offsetY / 300);
計算縮小系數: MAX(0.45, 1 – offsetY / 300);
[解析]:假設正常狀態下用戶頭像的大小為70,當放大到最大時,不得超過105;當縮小到最小時,不得小于31.5.則這個最大倍數1.5就是我們期望用戶頭像可放大的最大值除以正常狀態下的值,即105/70.0=1.5。同樣,最小倍數0.45計算公式為:31.5 / 70.0 = 0.45.
2.為了保證在縮放過程中,y坐標不變,那么就需要動態地更新y坐標,也就是在縮放時,將y坐標固定。
代碼實現
- 首先,我們給導航欄添加一個titlteView:
UIView *titleView = [[UIView alloc] init];
self.navigationItem.titleView = titleView;
self.headerImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"head.jpg"]];
self.headerImageView.layer.cornerRadius = 35;
self.headerImageView.layer.masksToBounds = YES;
self.headerImageView.frame = CGRectMake(0, 0, 70, 70);
// 這一句話非常重要,保證用戶頭像水平居中
self.headerImageView.center = CGPointMake(titleView.center.x, 0);
[titleView addSubview:self.headerImageView];
-
[疑惑]:
這里為什么不直接將headerImageView作為titleView呢?因為titleView會自動被系統給設置大小了,而我們的頭像是固定大小的,可以可自由調整的,因此我們只能作為一個單獨的控件放在titleView上。
接下來最關鍵的代碼就是在滾動時處理縮放用戶頭像的了:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y + scrollView.contentInset.top;
CGFloat scale = 1.0;
// 放大
if (offsetY < 0) {
// 允許下拉放大的最大距離為300
// 1.5是放大的最大倍數,當達到最大時,大小為:1.5 * 70 = 105
// 這個值可以自由調整
scale = MIN(1.5, 1 - offsetY / 300);
} else if (offsetY > 0) { // 縮小
// 允許向上超過導航條縮小的最大距離為300
// 為了防止縮小過度,給一個最小值為0.45,其中0.45 = 31.5 / 70.0,表示
// 頭像最小是31.5像素
scale = MAX(0.45, 1 - offsetY / 300);
}
self.headerImageView.transform = CGAffineTransformMakeScale(scale, scale);
// 保證縮放后y坐標不變
CGRect frame = self.headerImageView.frame;
frame.origin.y = -self.headerImageView.layer.cornerRadius / 2;
self.headerImageView.frame = frame;
}
知識點擴展:
1.用Content Insets對窗口稍作調整
contentInset屬性可以改變content offset的最大和最小值,這樣便可以滾動出可滾動區域。它的類型為UIEdgeInsets,包含四個值:{top,left,bottom,right}。當你引進一個inset時,你改變了content offset的范圍。比如,設置content inset頂部值為10,則允許content offset的y值達到10。
2.contentInset是scrollview的contentview的頂點相對于scrollview的位置,例如你的contentInset = (0 ,100),那么你的contentview就是從scrollview的(0 ,100)開始顯示.
3.CGRectZero 是一個(0,0,0,0)的矩形常量。需要創建邊框但還不確定邊框大小和位置時,可以使用此常量。
結束語
終于,這個demo終于敲完了一遍,感謝標哥,最后自己簡單的封裝了一下,以后直接用就可以。
- 用法:
1.導入類 ZYScaleTitleView 到您的工程中
2.在所需界面中,導入頭文件 #import "ZYScaleTitleView.h"
@property(strong,nonatomic)ZYScaleTitleView *ZYtitleView;
3.在viewDidLoad中
self.ZYtitleView = [[ZYScaleTitleView alloc]initWithTitleViewImageName:@"114"];
self.navigationItem.titleView = self.ZYtitleView;
4.在ViewDidScroll:中調去
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self.ZYtitleView ScaleTitleView:scrollView];
} - 已于2016于8月3日更新一次
Demo地址:https://github.com/RenZhengYang/ZYScaleNavTitleView
如有不足,請指點,虛心學習,互相交流。歡迎點星,鼓勵!!!