頭部視圖拉伸放大效果實現(xiàn)原理解析

stretchableView.gif

在很多APP中大家應(yīng)該都見過一些類似個人主頁的頁面,下邊是tableview列表答捕,上邊的頭部視圖可以拉伸放大.

在一番研究實現(xiàn)了這個拉伸效果后禀忆,順便把這個功能進行了封裝,使用時只需兩行代碼

1.初始化調(diào)用

stretchableView = LPStretchableHeaderView(stretchableView: bgImageView)

2.代理方法實現(xiàn):

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    stretchableView.scrollViewDidScroll(scrollView)
}

github代碼demo


下邊是實現(xiàn)原理的解析营袜,大神請繞路~~~

實現(xiàn)原理解析

一:設(shè)置頭部視圖
創(chuàng)建imageView,并添加到控制器的view上

由于在往下拖動列表時丑罪,頭部視圖的y值是沒有跟著下移的荚板,所以肯定不能讓它作為tableview的tableHeaderView凤壁,只能把上邊的圖片視圖添加到Controller的view上

二:設(shè)置tableview
  • 創(chuàng)建一個跟頭部視圖同樣大小的空視圖headerView作為tableview的tableHeaderView,來填充頭部圖片視圖區(qū)域
  • 把tableview的背景顏色設(shè)置為clearColor跪另,這樣就可以看到下面的頭部圖片了

這樣一來拧抖,我們的列表視圖的實際大小就占據(jù)了整個屏幕,并且不影響看到下面的頭部圖片免绿,而且在頭部圖片區(qū)域拖動的時候(實際拖動的是列表的tableHeaderView)也可以觸發(fā)列表的滾動事件唧席,同時上滑的時候列表的頂部滾動區(qū)域也達到了導(dǎo)航欄位置,一石好幾鳥啊~??

三:頭部視圖添加子控件

一般在頭部視圖的圖片上方嘲驾,還會顯示昵稱淌哟、頭像等信息,我們需要把這些子控件添加到剛才創(chuàng)建的空視圖headerView

注意:不要添加到頭部視圖的imageView中辽故!

因為稍后我們在在拉伸列表時徒仓,會改變imageView的frame,但是并沒有改變其內(nèi)的子控件的frame誊垢,所以子控件位置會發(fā)生錯亂掉弛。

現(xiàn)在控件布局如下:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 頭部圖片視圖
    bgImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_WIDTH * imageRatio))
    bgImageView.image = UIImage(named: "123")
    view.addSubview(bgImageView)
    
    // 列表
    tableView = UITableView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT))
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
    tableView.dataSource = self
    tableView.delegate = self
    tableView.showsVerticalScrollIndicator = false
    tableView.backgroundColor = UIColor.clear // 注意要清除列表的背景顏色
    view.addSubview(tableView)
    
    // 創(chuàng)建一個空白view來進行填充tableHeaderView
    let headerView = UIView(frame: bgImageView.bounds)
    tableView.tableHeaderView = headerView
    
    // 添加label子控件
    let nameLabel = UILabel(frame: CGRect(x: 0, y: 150, width: bgImageView.width, height: 40))
    nameLabel.text = "哈哈哈??"
    nameLabel.textAlignment = .center
    nameLabel.textColor = UIColor.white
    headerView.addSubview(nameLabel) // 注意要把子控件添加到headerView中
    
    // 導(dǎo)航欄
    makeNavView()
}
三:實現(xiàn)滾動拉伸放大效果
  • 下拉時通過tableview在y軸的偏移量來決定頭部圖片的高度拉伸多少
  • 通過圖片拉伸的高度及圖片原來的寬高比例計算出要拉伸的寬度
  • 通過圖片拉伸后的寬度計算出x值應(yīng)向左的偏移量

1)首先,我們會在頭部視圖初始化的時候記錄它的原始frame喂走,這個后邊會用到

// 圖片的原始frame
originFrame = bgImageView.frame

2)取出列表y值的偏移量

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let yOffset = scrollView.contentOffset.y
}

3)圖片拉伸后的高度

// 下拉時yOffset值是負數(shù)殃饿,所以需要減
frame.size.height = originFrame.size.height - yOffset

4)圖片拉伸后的寬度

// 通過圖片的寬高比imageRatio及拉伸后的高度等比計算新寬度
frame.size.width = frame.size.height / imageRatio

5)x值的位置重新計算

// 圖片寬高同時變大后,圖片會整體向右偏移芋肠,所以需要重新計算x值
frame.origin.x = originFrame.origin.x - (frame.size.width - originFrame.size.width) * 0.5

當(dāng)列表上滑時乎芳,移動頭部圖片跟著向上移動

var frame = originFrame
frame.origin.y = originFrame.origin.y - yOffset
bgImageView.frame = frame

最終,處理代碼為:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
    let yOffset = scrollView.contentOffset.y
    
    // 頭部圖片拉伸設(shè)置
    if yOffset > 0 { // 上滑
        var frame = originFrame
        frame.origin.y = originFrame.origin.y - yOffset
        bgImageView.frame = frame
        
    } else { // 下拉
        var frame = originFrame
        frame.size.height = originFrame.size.height - yOffset
        frame.size.width = frame.size.height / imageRatio
        frame.origin.x = originFrame.origin.x - (frame.size.width - originFrame.size.width) * 0.5
        bgImageView.frame = frame
    }
}



封裝

通過以上實現(xiàn)可以看出业栅,所有的操作都是通過拿到scrollViewDidScroll回調(diào)方法中列表y軸的偏移量秒咐,然后對頭部視圖bgImageView的frame進行更改實現(xiàn)的谬晕。

所以其實沒啥好封裝的碘裕,如果非得封裝的話,那就只需要把bgImageView控件和對它frame更改的操作拿出去就ok了攒钳。

于是我建了一個工具類LPStretchableHeaderView帮孔,實現(xiàn)如下:

LPStretchableHeaderView.swift文件

import UIKit

public class LPStretchableHeaderView: NSObject {

    private var stretchView = UIView()
    private var imageRatio: CGFloat
    private var originFrame = CGRect()
    
    public init(stretchableView: UIView) {
        
        stretchView = stretchableView
        originFrame = stretchableView.frame
        imageRatio = stretchableView.bounds.height / stretchableView.bounds.width
    }
    
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        let yOffset = scrollView.contentOffset.y
        if yOffset > 0 { // 往上移動
            var frame = originFrame
            frame.origin.y = originFrame.origin.y - yOffset
            stretchView.frame = frame
        } else { // 往下移動
            var frame = originFrame
            frame.size.height = originFrame.size.height - yOffset
            frame.size.width = frame.size.height / imageRatio
            frame.origin.x = originFrame.origin.x - (frame.size.width - originFrame.size.width) * 0.5
            stretchView.frame = frame
        }
    }
}

這樣,以后遇到有這種需求的頁面不撑,兩行代碼就搞定了~


如果感覺有幫助就點個??鼓勵下吧??
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末文兢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焕檬,更是在濱河造成了極大的恐慌姆坚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件实愚,死亡現(xiàn)場離奇詭異兼呵,居然都是意外死亡兔辅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門击喂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來维苔,“玉大人,你說我怎么就攤上這事懂昂〗槭保” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵凌彬,是天一觀的道長沸柔。 經(jīng)常有香客問我,道長饿序,這世上最難降的妖魔是什么勉失? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮原探,結(jié)果婚禮上乱凿,老公的妹妹穿的比我還像新娘。我一直安慰自己咽弦,他們只是感情好徒蟆,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著型型,像睡著了一般段审。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闹蒜,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天寺枉,我揣著相機與錄音,去河邊找鬼绷落。 笑死姥闪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的砌烁。 我是一名探鬼主播筐喳,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼函喉!你這毒婦竟也來了避归?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤管呵,失蹤者是張志新(化名)和其女友劉穎梳毙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐下,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡账锹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年堂氯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牌废。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡咽白,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸟缕,到底是詐尸還是另有隱情晶框,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布懂从,位于F島的核電站授段,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏番甩。R本人自食惡果不足惜侵贵,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缘薛。 院中可真熱鬧窍育,春花似錦、人聲如沸宴胧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恕齐。三九已至乞娄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間显歧,已是汗流浹背仪或。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留士骤,地道東北人范删。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像敦间,于是被迫代替她去往敵國和親瓶逃。 傳聞我的和親對象是個殘疾皇子束铭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫廓块、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,066評論 4 62
  • 親愛的陸鈺你好: 今天是挺有趣的一天契沫,早晨因為老公貼心地主動送東東去上英語課带猴,讓你有時間去apple專賣店修理破碎...
    常拓閱讀 203評論 3 7
  • 1、SMART原則:適用于目標(biāo)設(shè)定懈万、任務(wù)委派 Specific 具體明確的 Measurable 可衡量的 Ach...
    行者潘閱讀 2,036評論 0 3
  • 如果東海水全部下成雨拴清, 落到火焰山靶病, 是山火被澆滅, 還是海水被烘干口予? 每隔幾年娄周, 會有一批老實忠厚的字眼, 從教...
    青舟青舟閱讀 111評論 0 4
  • 實際上編程并不像大家想象中的那樣you多深奧沪停,you多難懂煤辨。似乎只you站在業(yè)界最前沿的一小撮人士才能辦到。其實只...
    NEYO_47a8閱讀 501評論 0 0