iOS-跟著標哥微博&學習導航頭像縮放

引言:今天就花半個小時的時間,學習一下標哥的導航頭像縮放,小總結一下,若是侵了標哥的權,請見怪,及時提醒,本篇僅供學習。

就如標哥,微博所說,在很多App中,經常存在一種需求就是,界面上下滾動時用戶頭像也跟著變化,而用戶頭像是放在系統的導航條上的。也有很多人,嘗試自定義View,但是標哥,說了,沒有必要,直接用系統的便可。(雖然,我不太認識標哥,哈哈)。

  • 要學到的知識點:
    - 如何分析實現原理
    - 如何實現縮放效果
    - 如何將計算縮放系數
  • 跟著效果圖一探究竟
    如圖所示,要明白兩點:
    一、是當往下滾動時,在一定范圍內,會放大頭像,但是不會放得過大;
    二、在往上滾動時,在一定范圍內,會縮小頭像,但是不會縮小得過小:
titleView放大縮小.gif

這說明了什么呢?頭像的縮放和放大都是有上、下限的,而且,頭像的起點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
如有不足,請指點,虛心學習,互相交流。歡迎點星,鼓勵!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容