- 先上效果图,希望对你有帮助:不论难易,坚持是一种态度。
- 分类可实现多种效果:可控导航栏是否 隐藏,是只拉取高度,还是拉取宽高
。。。。。。。。
- headerAllowScrolled 控制:头部视图 是否 跟随滚动
UIScrollView+topScaleHeaderView.swift 分类抽取
- 在这里 我要 用到查看 导航控制器的 导航栏 是否隐藏 ,所以我 抽取了一个 UIView的分类
extension UIView{
/**
找到 当前 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 // 默认 topScaleHeaderView 的高度
var scaleType_key = 2 // 1: 只变高度拉伸,2:宽高度拉伸
extension UIScrollView: UIScrollViewDelegate {
//MARK: - 提供 扩展 只读 属性
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) {
// 设置 头部伸缩视图
self.willChangeValueForKey("headerView_Key")
objc_setAssociatedObject(self, &headerView_Key, topScaleHeaderView, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.didChangeValueForKey("headerView_Key")
self.addSubview(topScaleHeaderView)
// 设置 头部视图 最大Y值
self.willChangeValueForKey("headerView_MaxY_key")
objc_setAssociatedObject(self, &headerView_MaxY_key, getNavMaxY(), objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
self.didChangeValueForKey("headerView_MaxY_key")
// 设置 头部伸缩视图 高度, 若:不传高度,默认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 监听scrollView 滚动时 contentOffset改变
self.addObserver(self, forKeyPath: "contentOffset", options: .New, context: nil)
// 设置头部视图,是否跟随 scrollview视图滚动
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{ // 有导航
if currentVC.navigationController!.navigationBarHidden{ // 隐藏
navMaxY = 0
}else{ // 未 隐藏
navMaxY = 64
}
}
}
return navMaxY
}
public func scrollViewDidScroll(scrollView: UIScrollView) {
// 导航 未 隐藏,var offsetY = scrollView.contentOffset.y
// 导航 隐藏, 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"))
// 若 未 设置高度 为: 默认高度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 拉伸头部视图,
// 我们可以设置 topScaleHeaderView的高度,未设置为 默认分类中的headerView_H_Default,
// headerAllowScrolled代表:头部视图 是否 随scrollView及其子类 滚动
// 当然:你也可以 配置 分类中的 scaleType_key = 1 // 默认 1: 只变高度拉伸,2:宽高度拉伸,我这里配置的是全局的,你也可以自己 扩展一个属性来控制每个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
}
}
网友评论