參考資料: iOS 高仿支付寶 9.x 版本首頁(yè)
但是我跟參考資料中作者關(guān)于整個(gè)頁(yè)面的設(shè)計(jì)邏輯不一致, 但是實(shí)現(xiàn)的效果一樣, 也算是多一種實(shí)現(xiàn)方式, 希望跟大家一起共同學(xué)習(xí).
先上效果
整個(gè)界面的結(jié)構(gòu)圖
關(guān)于整個(gè)頁(yè)面布局邏輯, 從上往下說(shuō):
1.頂部: "類(lèi)導(dǎo)航欄", 因?yàn)槠洳⒉皇菍?dǎo)航欄, 只是一個(gè)跟導(dǎo)航欄尺寸一致的View, 所以進(jìn)入這個(gè)頁(yè)面的時(shí)候需要將自帶的導(dǎo)航欄隱藏掉. 此部分共三層, 從底層往上依次是: 底色View(藍(lán)色背景色), 掃一掃View(剛開(kāi)始隱藏, 向上滾動(dòng)后逐漸顯示), 搜索框View.
2. tableView, 緊接著就是一個(gè)帶有tableHeaderView的tableView, 其tableHeaderView高度與添加到tableView上顯示主要功能的view的尺寸一致.
注意細(xì)節(jié): 在整個(gè)向上緩慢滑動(dòng)的過(guò)程中, 會(huì)發(fā)現(xiàn)頂部圖標(biāo)的隱藏/顯示變化過(guò)程分為三個(gè)部分: 1. 搜索框view快速消失, 2.搜索框view后緊接著另一個(gè)"類(lèi)導(dǎo)航"view(掃一掃 + 付錢(qián) + 搜索 + "+")逐漸顯示, 3. 下面的四個(gè)主要功能模塊逐漸消失, 當(dāng)滑動(dòng)到導(dǎo)航欄位置時(shí), 徹底消失. 并且, 當(dāng)四個(gè)主要功能模塊完全消失的時(shí)候, 此時(shí)手離開(kāi)屏幕, 其會(huì)自動(dòng)向上滾動(dòng)到四個(gè)主要功能模塊完全消失的位置.
關(guān)鍵代碼:
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let offentY = scrollView.contentOffset.y
// 此處之所以以24為判斷依據(jù), 主要是因?yàn)橐c下面設(shè)置alpha保持一致, 1 - 24 / 95 約等于 0.75
if offentY > 0 && offentY < 24 {
tableView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
} else if offentY >= 24 && offentY < 95 {
tableView.setContentOffset(CGPoint(x: 0, y: 95), animated: true)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
if offsetY <= 0 {
headerView.frame = CGRect(x: 0, y: offsetY, width: SCREEN_WIDTH, height: 305)
childVC?.changeAlpha(alpha: 1)
coverNavView.alpha = 0
mainNavView.alpha = 1
} else if offsetY > 0 && offsetY < 95 {
//處理透明度
let alpha = (1 - offsetY / 95) > 0 ? (1 - offsetY / 95) : 0
childVC?.changeAlpha(alpha: alpha / 3)
if alpha > 0.9 { // 為了原顯示內(nèi)容可以快速消失, 增加后面有更長(zhǎng)的顯示時(shí)長(zhǎng)
coverNavView.alpha = 0
mainNavView.alpha = alpha / 5
} else {
mainNavView.alpha = 0
coverNavView.alpha = 1 - alpha
if alpha <= 0.75 {
childVC?.changeAlpha(alpha: 0)
}
}
}
}
使用MJRefresh時(shí)注意一個(gè)點(diǎn)
tableView.mj_header = MJRefreshNormalHeader { [weak self] in
guard let weak = self else {return}
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
// Put your code which should be executed with a delay here
weak.tableView.mj_header.endRefreshing()
weak.dataSorceNumber = 10
weak.tableView.reloadData()
})
}
//重點(diǎn): 由于頂部有305高度的tableHeaderView, 并且在設(shè)置的時(shí)候, 將tableView的scrollIndicatorInsets的top值設(shè)置為305, 所以需要忽略這部分高度, 才可以正常顯示下拉刷新動(dòng)畫(huà).
tableView.mj_header.ignoredScrollViewContentInsetTop = -305
tableView.mj_footer = MJRefreshAutoNormalFooter { [weak self] in
guard let weak = self else {return}
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
weak.tableView.mj_footer.endRefreshing()
weak.dataSorceNumber += 10
weak.tableView.reloadData()
})
}