翻譯篇:實現(xiàn)Twitter個人詳情動態(tài)效果

原文由ariok發(fā)表宠蚂,地址是implementing-the-twitter-ios-app-ui

效果圖如下:

效果圖

原來作者的代碼會存在一個概現(xiàn)Bug:當(dāng)快速下拉時,個人頭像并不會立刻顯示在HeaderView上方童社,我已經(jīng)向作者提交了Pull requests

編譯過程中會發(fā)生錯誤肥矢,因為swift更新了,所以需要自己解決下錯誤叠洗。

翻譯的比較差甘改,因為不做閱讀理解好多年了。灭抑。十艾。重點在效果。腾节。忘嫉。

結(jié)構(gòu)描述

在編碼之前,我將對UI的結(jié)構(gòu)做一個簡單的介紹案腺。

打開Main.storyboard文件庆冕。在唯一的一個控制器view中,你可以發(fā)現(xiàn)兩個主要的對象劈榨。第一個是顯示Header的視圖访递,第二個是一個包含個人頭像(我們叫它Avatar)和其他與賬號相關(guān),比如用戶名同辣、follow按鈕的ScrollView拷姿。Sizer控件只是用來確認(rèn)ScrollView內(nèi)容是否能進(jìn)行垂直滾動。

就像你所看到的旱函,這個結(jié)構(gòu)非常簡單响巢。需要的注意的是,我將Header放在ScrollView外面棒妨,而不是把它和其他ScrollView子控件放在一起踪古。因為這樣做可以讓這個結(jié)構(gòu)具備更好的擴(kuò)展性。

開始編碼

如果你仔細(xì)看完動畫券腔,你會注意到你可以管理兩個不同的動作:

  1. 用戶下拉(當(dāng)ScrollView內(nèi)容已經(jīng)在屏幕的頂部時)

  2. 用戶上/下滾動

這個動作可以分解成四步:

2.1) 向上滾動伏穆,Header控件縮小直到它的尺寸和導(dǎo)航欄默認(rèn)尺寸相等,然后這個Header控件就會粘在屏幕的上方

2.2) 向上滾動颅眶, Avatar(頭像)逐漸變小

2.3) 當(dāng)Header控件和ScrollView的子控件重疊時蜈出,Avatar(頭像)在Header控件底部

2.4) 當(dāng)用戶名Label的頂部和Header控件底部重疊時,一個新的白色Label將會從Header控件的中底部顯示涛酗。并且Header控件的圖片變模糊铡原。

打開ViewController.swift偷厦,讓我們一步一步地實現(xiàn)這些功能

設(shè)置控制器

第一件需要去做的事是獲取ScrollView的offset信息。通過實現(xiàn)UIScrollViewDelegate協(xié)議的scrollViewDidScroll方法燕刻,我們可以很容易地做到這一點只泼。

一種最簡單的展示一個view上變化的方式是使用CoreAnimation三維變換,并且設(shè)置新值給layer.transform屬性卵洗。

這個關(guān)于CoreAnimation的教程可能會讓它變得簡便:

http://www.thinkandbuild.it/playing-around-with-core-graphics-core-animation-and-touch-events-part-1/.

以下是scrollViewDidScroll方法的第一部分:

let offset = scrollView.contentOffset.y
var avatarTransform = CATransform3DIdentity
var headerTransform = CATransform3DIdentity

我們可以在這個方法里面獲取當(dāng)前的豎直偏移请唱,并且初始化兩個將要在方法后面設(shè)置的轉(zhuǎn)換信息。

下拉

讓我們對下拉動作進(jìn)行處理:

if offset < 0 {
    
    let headerScaleFactor:CGFloat = -(offset) / header.bounds.height
    let headerSizevariation = ((header.bounds.height * (1.0 + headerScaleFactor)) - header.bounds.height)/2.0
    headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizevariation, 0)
    headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
    
    header.layer.transform = headerTransform
}

首先过蹂,我們檢查偏移量是否為負(fù)數(shù)十绑,即ScrollView是否已出現(xiàn)彈性區(qū)域。

剩下的代碼是一些簡單的數(shù)學(xué)運算酷勺。

這個Header控件需要放大來保持它的上邊緣和屏幕頂部相對固定本橙,并且這個圖片是從底部開始放大的。

總的來說脆诉,這個變換主要由縮放甚亭,然后轉(zhuǎn)化view的尺寸變化為到頂部的距離構(gòu)成。事實上击胜,你可以朝屏幕頂端移動ImageView圖層的中點并且進(jìn)行縮放來相同的效果亏狰。

使用一個屬性來對頭部縮放比例進(jìn)行計算。我們希望Header控件參照偏移量進(jìn)行適當(dāng)?shù)目s放偶摔。換種說法:當(dāng)偏移量為Header視圖控件的兩倍時暇唾,頭部縮放比例應(yīng)該設(shè)置為2.0。

我們需要處理的第二個動作是上下滾動啰挪。讓我們看看如何一步一步地完成主要視圖的變換信不。

Header(第一階段)

當(dāng)前的偏移量應(yīng)該大于0嘲叔。Header控件應(yīng)該根據(jù)以下的偏移量來進(jìn)行豎直移動亡呵,直到它到達(dá)指定高度(我們下面將會對Header模糊進(jìn)行講解)。

headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offset_HeaderStop, -offset), 0)

這段代碼真的是很簡單硫戈。我們只需要設(shè)置Header控件偏移一個最小值锰什,Header控件將會在offset_HeaderStop這個點停止移動。

因為我比較懶丁逝,所以我寫死了一些數(shù)值汁胆,比如offset_HeaderStop。我們可以通過更加優(yōu)雅的方式霜幼,比如計算UI控件的位置來實現(xiàn)相同的效果嫩码。或許在下一次我會試試罪既。

AVATAR(頭像)

這個頭像(圖片)以和下拉相同的邏輯進(jìn)行縮放铸题,只是在這種情況下铡恕,圖片是和底部貼合而不是頂部。這段代碼和上面比較相似丢间,除了減小縮放的比例為1.4探熔。

let avatarScaleFactor = (min(offset_HeaderStop, offset)) / avatarImage.bounds.height / 1.4 // Slow down the animation
let avatarSizeVariation = ((avatarImage.bounds.height * (1.0 + avatarScaleFactor)) - avatarImage.bounds.height) / 2.0
avatarTransform = CATransform3DTranslate(avatarTransform, 0, avatarSizeVariation, 0)
avatarTransform = CATransform3DScale(avatarTransform, 1.0 - avatarScaleFactor, 1.0 - avatarScaleFactor, 0)

就像你看到的,當(dāng)Header控件停止變化時烘挫,我們通過min函數(shù)來停止對個人頭像的縮放(offset_HeaderStop)诀艰。

此時,我們根據(jù)當(dāng)前的偏移量來設(shè)置最頂層的圖層饮六。除非偏移量大于等于offset_HeaderStop其垄,否則頂部圖層始終是個人頭像。當(dāng)偏移量大于offset_HeaderStop卤橄,這個圖層就變成了Header控件捉捅。

if offset <= offset_HeaderStop {
    
    if avatarImage.layer.zPosition < header.layer.zPosition{
        header.layer.zPosition = 0
    }
    
}else {
    if avatarImage.layer.zPosition >= header.layer.zPosition{
        header.layer.zPosition = 2
    }
}

白色Label

以下是白色Label執(zhí)行動畫的代碼:

let labelTransform = CATransform3DMakeTranslation(0, max(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0)
headerLabel.layer.transform = labelTransform

這里介紹兩個新的變量:當(dāng)偏移量等于offset_B_LabelHeader時,這個黑色的用戶名Label剛好到達(dá)Header視圖的底部虽风。

distance_W_LabelHeader是Header控件的底部和Header中的白色Label中點的距離棒口。


這個轉(zhuǎn)換通過以下邏輯進(jìn)行計算:黑色Label一旦喝Header控件相交,白色Label就立即顯示辜膝,并且白色Label到達(dá)Header控件的中點時停止无牵。所以使用以下代碼來創(chuàng)建Y的偏移:

max(-distance_W_LabelHeader, offset_B_LabelHeader - offset)

模糊

最后一個效果是模糊Header控件。為了得到合適的解決方案厂抖,我使用了三個不同的庫...我還嘗試創(chuàng)建自己的OpenGL ES茎毁,但是實時更新模糊效果總是非常遲緩。

我了解到我可以只對模糊進(jìn)行一次計算忱辅,讓模糊和非模糊的圖片進(jìn)行重疊七蜘,并且改變透明度值。我很確定墙懂,這就是Twitter采用的方法橡卤。

在viewDidAppear中我們計算模糊的Header并且通過設(shè)置透明度為0來進(jìn)行隱藏。

headerBlurImageView = UIImageView(frame: header.bounds)
headerBlurImageView?.image = UIImage(named: "header_bg")?.blurredImageWithRadius(10, iterations: 20, tintColor: UIColor.clearColor())
headerBlurImageView?.contentMode = UIViewContentMode.ScaleAspectFill
headerBlurImageView?.alpha = 0.0
header.insertSubview(headerBlurImageView, belowSubview: headerLabel)

模糊的view可以使用FXBlurView得到损搬。

在scrollViewDidScroll方法中碧库,我們只需要根據(jù)偏移量來更新透明度就行了。

headerBlurImageView?.alpha = min (1.0, (offset - offset_B_LabelHeader)/distance_W_LabelHeader)

以上計算邏輯主要為:透明度最大值必須為1巧勤,模糊效果必須在黑色Label到達(dá)Header控件時出現(xiàn)嵌灰,在白色Label停止后停止加深模糊。

源碼地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颅悉,一起剝皮案震驚了整個濱河市沽瞭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剩瓶,老刑警劉巖驹溃,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柒瓣,死亡現(xiàn)場離奇詭異,居然都是意外死亡吠架,警方通過查閱死者的電腦和手機(jī)芙贫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傍药,“玉大人磺平,你說我怎么就攤上這事」樟桑” “怎么了拣挪?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長俱诸。 經(jīng)常有香客問我菠劝,道長,這世上最難降的妖魔是什么睁搭? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任赶诊,我火速辦了婚禮,結(jié)果婚禮上园骆,老公的妹妹穿的比我還像新娘舔痪。我一直安慰自己,他們只是感情好锌唾,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布锄码。 她就那樣靜靜地躺著,像睡著了一般晌涕。 火紅的嫁衣襯著肌膚如雪滋捶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天余黎,我揣著相機(jī)與錄音重窟,去河邊找鬼。 笑死驯耻,一個胖子當(dāng)著我的面吹牛亲族,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播可缚,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斋枢!你這毒婦竟也來了帘靡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤瓤帚,失蹤者是張志新(化名)和其女友劉穎描姚,沒想到半個月后涩赢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡轩勘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年筒扒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绊寻。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡花墩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出澄步,到底是詐尸還是另有隱情冰蘑,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布村缸,位于F島的核電站祠肥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏梯皿。R本人自食惡果不足惜仇箱,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望东羹。 院中可真熱鬧工碾,春花似錦、人聲如沸百姓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垒拢。三九已至旬迹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間求类,已是汗流浹背奔垦。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留尸疆,地道東北人椿猎。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像寿弱,于是被迫代替她去往敵國和親犯眠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

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