試著自己製作類似Twitter會員資料頁面的效果時查了很多資料, 大多的資訊幾乎都是要使用第三方套件,或是使用純程式碼的方式建立UI。 較少看到用StoryBoard和Xib的方式來建立,所以這次挑戰把純程式碼改成用StoryBoard來建立同樣效果的UI。 這個範例只說明原理,並不表示為一個最佳的做法,純粹分享和交流。 當然如果有更好的方法還請不吝指教。 這種類型的UI畫面可以做很多種不同的變化,想自己挑戰的人可以自由發揮。
我這個範例參考的文章在最後有附連結,邏輯上我有修改一些,不過觀念上還是一樣的,如果不想用StoryBoard佈局可以參考他們的方式。
- 將下、左、右的約束設為0,上方約束設定方式會比較不一樣,不要對齊Safe Area,對齊最底層的UIView上方設為0。
- 然後這一步很重要在StroyBoard 選單中找出Content Insets參數預設是Automatic,改成Never。
- 首先從StoryBoard UI工具中拖曳一個UIView元件,當作HeaderView,記得不要放在TableView內部,要和TableView在同一個階層,並放在上層蓋過TableView。
- 接著設定該UIView的約束,只需要設定上、左、右的約束,左、右約束設為0,然後高度要設定多少看個人需要,此範例設定為110。
- 上邊約束對齊(Top Align)TableView上邊(右鍵從HeaderView拖曳到TableView上就可以看到設定選單)。
- 並設定四邊的約束都為0。
- 然後在StoryBoard選單找出Content Mode參數改成Aspect Fill。
- 先拖曳一個UIView到TableView中,讓其成為TableView的HeaderView,接著把一個UIImageView放到該UIView中。
- 最後固定寬度和高度,此範例設定為69 * 69,最後設定對齊左邊和上邊的約束,左邊為40、上邊為 -40,就完成畫面的佈局。
offsetHeaderStop是設定希望將HeaderView上推倒多少高度停止所使用的變數,範例中會停止在和Navigation Bar 加上StatusBar一樣的高度,當然如果有其他高度想要使用可直接針對這個變數修改。
private var offsetHeaderStop:CGFloat = 0 //Header上推到多少高度停止
//在ViewDidLoad中
override func viewDidLoad() {
super.viewDidLoad()
//navigationBar高度(44)+ statusBar高度(20或44)
//navigationBar在有無瀏海的機種都一樣是44
//statusBar在無瀏海的機種是20、有瀏海的機種是44
let offsetGap = (navigationController?.navigationBar.frame.height)! + (UIApplication.shared.statusBarFrame.height) // navigationBar高度 (44)+ statusBar高度(20或44)
//110 - 64或88
offsetHeaderStop = headerView.frame.height - offsetGap
........
//TableView contentInset的Top需要設定和HeaderView的高度一樣畫面才會正常
tableView.contentInset.top = headerView.frame.height
........
}
接著就是UITableViewDelegate或是UIScrollViewDelegate的scrollViewDidScroll方法,需要自行寫滑動的轉換行為。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//多加headerView的height是因為tableView的contentInset top並不是0,所以在Scroll的時候起始位置還是從0開始scrollView contentOffset y與內容物起始點的位置不同,才導致動畫會很不順暢
//使用TableView會和ScrollView會有些在offset會有不同的位移需要
let offset = scrollView.contentOffset.y + headerView.bounds.height
//分別要給HeaderView和大頭照用的transformation
var headerTransform = CATransform3DIdentity
var avatarTransform = CATransform3DIdentity
// PULL DOWN(下拉)
// 下拉到頂部後繼續下拉,HeaderView的圖片會有放大的效果
if offset < 0 {
let headerScaleFactor:CGFloat = -(offset) / headerView.bounds.height
let headerSizevariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizevariation, 0)
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
// Hide views if scrolled super fast
headerView.layer.zPosition = 0
} else { // SCROLL UP/DOWN ------------
// Header View -----------
headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offsetHeaderStop, -offset), 0)
//大頭照 -----------
//大頭照在滑動到HeaderView固定時的交界處,大頭照會縮小而且會交換圖層順序
let avatarScaleFactor = (min(offsetHeaderStop, 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)
// headerView 和 avatarImage 的 z-position 位置調動
if offset <= offsetHeaderStop {
if avatarImage.layer.zPosition < headerView.layer.zPosition{
headerView.layer.zPosition = 0
}
}else if avatarImage.layer.zPosition >= headerView.layer.zPosition {
headerView.layer.zPosition = 2
}
}
// Apply Transformations
headerView.layer.transform = headerTransform
avatarImage.layer.transform = avatarTransform
}
上面都做完之後應該會發現,在有NavigationController的時候,NavigationBar會蓋住範例中的畫面,那麼就需要去隱藏或是修改顏色之類的屬性,將NavigationBar原本的背景色、下邊線等等屬性隱藏
關於官方提供的方法來NavigationBar的屬性,在換頁的時候會有一些問題存在。
最好是使用Method Swizzling來修改轉場效果與屬性會更適合。
這裡要注意,如果NavigationBar是使用Large Title模式的話,這個修改屬性的方法並不適用。
附上我參考的文章,或是可以看我整理在Extension檔案夾當中的UINavigationControllerExtension檔案
- https://www.thinkandbuild.it/implementing-the-twitter-ios-app-ui/
- http://nathanwhy.com/2015/03/02/2015-03-02-implementing-the-twitter-ios-app-ui/
如果要找一些第三方套件和英文的文章可以搜尋下列的關鍵字
關鍵字:Stretchy Header Effect、Twitter Effect、Parallax Effect、Sticky View、下拉圖片放大