- 先上效果圖,希望對(duì)你有幫助:不論難易,堅(jiān)持是一種態(tài)度。
- 分類可實(shí)現(xiàn)多種效果:可控導(dǎo)航欄是否 隱藏,是只拉取高度,還是拉取寬高
效果圖1:導(dǎo)航欄隱藏,只拉取高度.gif
效果圖2:導(dǎo)航欄顯示,拉取款高度.gif
。。。。。。。。
- headerAllowScrolled 控制:頭部視圖 是否 跟隨滾動(dòng)
效果圖: 頭部視圖跟隨滾動(dòng).gif
效果圖 頭部視圖 不跟隨其滾動(dòng).gif
UIScrollView+topScaleHeaderView.swift 分類抽取
- 在這里 我要 用到查看 導(dǎo)航控制器的 導(dǎo)航欄 是否隱藏 ,所以我 抽取了一個(gè) UIView的分類
extension UIView{
/**
找到 當(dāng)前 view 所在的 控制器
- returns: view 所在的 控制器
*/
func viewController() -> UIViewController?{
for(var next = self.superview; (next != nil); next = next!.superview){
let nextResponder = next?.nextResponder()
if ((nextResponder?.isKindOfClass(UIViewController.self)) != nil){
return (nextResponder as? UIViewController)!
}
}
return nil
}
}
- UIScrollView+topScaleHeaderView 分類
import UIKit
var headerView_Key = "headerView_Key"
var headerView_H_key = "headerView_H_key"
var headerAllowScrolled_Key = "headerAllowScrolled_Key"
var headerView_MaxY_key = "headerView_MaxY_key"
var headerView_H_Default: CGFloat = 250 // 默認(rèn) topScaleHeaderView 的高度
var scaleType_key = 2 // 1: 只變高度拉伸,2:寬高度拉伸
extension UIScrollView: UIScrollViewDelegate {
//MARK: - 提供 擴(kuò)展 只讀 屬性
var headerAllowScrolled: Bool?{
get{
if let _ = objc_getAssociatedObject(self, &headerAllowScrolled_Key){
return objc_getAssociatedObject(self, &headerAllowScrolled_Key) as? Bool
}
return true
}
}
var topScaleHeaderView_H: CGFloat{
get{
if let _ = objc_getAssociatedObject(self, &headerView_H_key){
return objc_getAssociatedObject(self, &headerView_H_key) as! CGFloat
}
return headerView_H_Default
}
}
var topScaleHeaderView: UIView?{
get{
return objc_getAssociatedObject(self, &headerView_Key) as? UIView
}
}
var topY: CGFloat{
get{
return objc_getAssociatedObject(self, &headerView_MaxY_key) as! CGFloat
}
}
//MARK: - 提供 配置 接口
func configBuildView(topScaleHeaderView:UIView, headerAllowScrolled: Bool? = true) {
// 設(shè)置 頭部伸縮視圖
self.willChangeValueForKey("headerView_Key")
objc_setAssociatedObject(self, &headerView_Key, topScaleHeaderView, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.didChangeValueForKey("headerView_Key")
self.addSubview(topScaleHeaderView)
// 設(shè)置 頭部視圖 最大Y值
self.willChangeValueForKey("headerView_MaxY_key")
objc_setAssociatedObject(self, &headerView_MaxY_key, getNavMaxY(), objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
self.didChangeValueForKey("headerView_MaxY_key")
// 設(shè)置 頭部伸縮視圖 高度, 若:不傳高度,默認(rèn)headerView_H_Default
let h = topScaleHeaderView.frame.size.height > 0 ? topScaleHeaderView.frame.size.height : headerView_H_Default
self.willChangeValueForKey("headerView_H_key")
objc_setAssociatedObject(self, &headerView_H_key, h, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
self.didChangeValueForKey("headerView_H_key")
print("self.topScaleHeaderView_H: \(self.topScaleHeaderView_H)")
self.contentInset = UIEdgeInsetsMake(self.topScaleHeaderView_H, 0, 0, 0)
self.topScaleHeaderView?.frame = CGRectMake(0, -self.topScaleHeaderView_H, topScaleHeaderView.frame.size.width, self.topScaleHeaderView_H)
// kvo 監(jiān)聽scrollView 滾動(dòng)時(shí) contentOffset改變
self.addObserver(self, forKeyPath: "contentOffset", options: .New, context: nil)
// 設(shè)置頭部視圖,是否跟隨 scrollview視圖滾動(dòng)
self.willChangeValueForKey("headerAllowScrolled_Key")
objc_setAssociatedObject(self, &headerAllowScrolled_Key, headerAllowScrolled, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
self.didChangeValueForKey("headerAllowScrolled_Key")
}
public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
self.scrollViewDidScroll(self)
}
private func getNavMaxY() -> CGFloat{
var navMaxY: CGFloat = 0
if let currentVC = self.viewController(){
if let _ = currentVC.navigationController{ // 有導(dǎo)航
if currentVC.navigationController!.navigationBarHidden{ // 隱藏
navMaxY = 0
}else{ // 未 隱藏
navMaxY = 64
}
}
}
return navMaxY
}
public func scrollViewDidScroll(scrollView: UIScrollView) {
// 導(dǎo)航 未 隱藏,var offsetY = scrollView.contentOffset.y
// 導(dǎo)航 隱藏, offsetY =scrollView.contentOffset.y + 64
self.topScaleHeaderView?.center.x = self.center.x
let offsetY = scrollView.contentOffset.y + self.topY
let scale = -offsetY/self.topScaleHeaderView_H < 1 ? 1 : -offsetY/self.topScaleHeaderView_H
if scaleType_key == 1{ // 只拉伸高度
self.topScaleHeaderView?.transform = CGAffineTransformMakeScale(1, scale)
}else{ // 高度寬度都拉伸
self.topScaleHeaderView?.transform = CGAffineTransformMakeScale(scale, scale)
}
self.topScaleHeaderView?.frame.origin.y = -self.topScaleHeaderView!.height
}
}
demo
import UIKit
class ScaleImageDemoViewController: UITableViewController {
let ScaleImageDemoViewController_CellID = "ScaleImageDemoViewController_CellID"
var topScaleHeaderView: UIImageView = {
let img = UIImageView(image: UIImage(named: "personIcon"))
// 若 未 設(shè)置高度 為: 默認(rèn)高度headerView_H_Default
img.height = 250
return img
}()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.setNavigationBarHidden(true, animated: true)
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.ScaleImageDemoViewController_CellID)
// 配置: 頭部拉伸 視圖:-》
// topScaleHeaderView 拉伸頭部視圖,
// 我們可以設(shè)置 topScaleHeaderView的高度,未設(shè)置為 默認(rèn)分類中的headerView_H_Default,
// headerAllowScrolled代表:頭部視圖 是否 隨scrollView及其子類 滾動(dòng)
// 當(dāng)然:你也可以 配置 分類中的 scaleType_key = 1 // 默認(rèn) 1: 只變高度拉伸,2:寬高度拉伸,我這里配置的是全局的,你也可以自己 擴(kuò)展一個(gè)屬性來控制每個(gè)scrollView及其子類的拉伸方式
self.tableView.configBuildView(self.topScaleHeaderView, headerAllowScrolled: false)
}
}
extension ScaleImageDemoViewController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(self.ScaleImageDemoViewController_CellID)
cell?.textLabel?.text = "\(indexPath.row )行"
cell?.backgroundColor = UIColor.whiteColor()
return cell!
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50
}
}