iOS开发------响应TableView下拉设置NavigationBar的透明度
来源:互联网 发布:好家伙 盗亦有道 知乎 编辑:程序博客网 时间:2024/06/07 16:27
最近工作不忙的时候会偷懒玩一会手机,会发现各大App中的一些小细节很吸引人,这次看到一个很有意思的效果,其实这个效果应用的已经很普遍,就是响应scrollView的下滑,NavigationBar从无到有(其实就是透明度从0到1的过程),看起来总是简单的,实现起来总会遇到点麻烦,这次也一样,经过查阅相关技术博客以及花点时间研究原理,也慢慢的理解实现了出来,个人还是觉得了解原理要比直接拿来代码要好的多,大体效果如下:
这里先附上代码的GitHub:https://github.com/YRunIntoLove/YSinaNavigationBarDemo
直接设置NavigationBar的背景颜色透明度----fail
首先想到的必然是直接修改背景(background)的alpha(透明度属性),即在scrollViewDidScroll中根据比例设置响应的透明度即可
self.navigationController?.navigationBar.backgroundColor = UIColor.orangeColor().colorWithAlphaComponent(alpha)
如果这么设置了,那么大家就和楼主一样想的太过简单了,尝试过后发现根本没有任何的效果,透明度没有任何的变化
设置NavigationBar的alpha----fail
如果设置背景颜色不能完成,那么我直接设置NavigationBar的透明度不就好了嘛
self.navigationController?.navigationBar.alpha = 0.3
这样子做当然可以,但是会发现一个小小的问题,就是贴在NavigationBar上的Title以及相关响应按钮等相关组件也会根据父视图的透明度变透明了,这似乎也不是咱们理想中的效果
利用runtime的关联属性,为NavigationBar添加一层自定义的视图层----Success
没有办法,打开百度一搜,果然会发现有很多这样子的尝试,最终还是需要动用runtime来自定义添加一个视图最为合适,动态关联属性算是runtime中很简单的知识了,花点时间了解一下也就会理解了,也可以在前面的博客 iOS开发----runtime关联对象(动态添加属性)中稍微的回顾一下。
首先需要新建一个NavigationBar的类目(拓展),因为最近学习Swift,代替Objective-C中类目的是Swift中的extension,需要在拓展中添加一个属性,说是属性,实际上是添加了一个get和set方法,自定义一个视图
var key:String = "CoverView"extension UINavigationBar{ var coverView:UIView?{ set{ //runtime添加动态关联的属性 objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } get{ //runtime读取动态关联的属性 return objc_getAssociatedObject(self, &key) as? UIView } }
/** * 设置 背景色 */@available(iOS 8.0,*)func setViewColor(color:UIColor){ //如果覆盖图层为nil if(self.coverView == nil) { //设置背景图片及度量 self.setBackgroundImage(UIImage(), forBarMetrics: .Default) //去除自定义背景图后形成的下端黑色横线 self.shadowImage = UIImage() //设置图层的frame let view = UIView(frame: CGRect(x: 0, y: -20, width: UIScreen.mainScreen().bounds.width, height: CGRectGetHeight(self.frame) + 20)) view.userInteractionEnabled = false//人机不交互 view.autoresizingMask = [.FlexibleWidth , .FlexibleHeight]//自适应宽度和高度 //将图层添加到导航Bar的底层 self.insertSubview(view, atIndex: 0) //因为这里不是一个真正的属性,是在runtime时进行关联的属性,所以相关属性的修改需要实例对象来"赋值" self.coverView = view } self.coverView?.backgroundColor = color}
这里说一下,其实Xcode提供给大家一个查看UI层次的功能<#楼主才知道,- - 感觉对Xcode的了解太差劲了#> Debug -> View Debuging -> Capture View Hierarchy
它可以让我们看到不少组件中私有属性,在这里可以看到NavigationBar的子视图中有这个一个子视图(_ UINavigationBarBackground),他的子视图中有一个UIImageView,也就是当我们设置背景图片或者背景色的时候,应该就是这个视图在响应。
当然设置透明度用上面的方法是可以的,在颜色中添加透明度即可,但是习惯性的还是写了一个接口
/** * 设置透明度 */@available (iOS 8.0, *)func setViewAlpha(alpha:CGFloat){ //如果view = self.coverView不成立,就return guard let view = self.coverView else { return } self.coverView!.backgroundColor = view.backgroundColor?.colorWithAlphaComponent(alpha)}
上面的效果因为push之后出现的NavigationBar的颜色不一样,所需的效果也不一样,所以为了避免影响之后NavigationBar的效果,需要写一个移除该图层的方法,如下
/** * 清除图层,视图消失时需要调用该方法,不然会影响其他页面的效果 */@available (iOS 8.0, *)func relieveCover(){ self.setBackgroundImage(nil, forBarMetrics: .Default) coverView?.removeFromSuperview() coverView = nil}
首先需要定义几个相关的属性
class CustomHeaderView: UIView { /// 代理 weak var delegate:CustomHeaderViewDelegate? ///底层控制ImageView缩放的View,后面通过更改它的frame属性来实现圆滑效果 var contentView:UIView! = UIView() /// 存放外部传入的视图,即ImageView var subView:UIView /// 最大的下拉距离 var maxContentOff:CGFloat /// 起点的纵坐标 private let originY:CGFloat = -64
接着实现自定义构造方法
init(subView:UIView,maxContentOff:CGFloat,headerViewSize: CGSize,delegate: CustomHeaderViewDelegate){ self.subView = subView//当前的imageView self.delegate = delegate self.maxContentOff = maxContentOff > 0 ? -maxContentOff : maxContentOff//因为向下滑动是负数,进行数字正负转换 super.init(frame: CGRectMake(0, 0, headerViewSize.width, headerViewSize.height)) //开始自动布局设置,意思是自动将subView的frame与superView相一致 subView.autoresizingMask = [.FlexibleTopMargin,.FlexibleBottomMargin,.FlexibleLeftMargin,.FlexibleRightMargin,.FlexibleWidth,.FlexibleHeight] //此视图不显示越界的视图 self.clipsToBounds = false self.contentView.frame = self.bounds self.contentView.addSubview(subView) //存放ImageView的视图需要显示越界的视图 self.contentView.clipsToBounds = true self.addSubview(contentView)}required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented")}
因为涉及到往外传值,所以必须使用回调,这里使用的是Delegate(委托)回调,当然是可以使用闭包传值的,定义协议如下:
protocol CustomHeaderViewDelegate : class{ /** 滚动已经到达最大偏移量,需要锁定滚动视图 :param: customHeaderView :param: maxContentOffSet 最大偏移量 */ @available(iOS 8.0,*) func customHeaderView(customHeaderView:CustomHeaderView,lockScrollView maxContentOffSet:CGFloat) /** 滚动过程中修改导航Bar的透明度 :param: customHeaderView :param: alpha 透明度 */ @available(iOS 8.0,*) func customHeaderView(customHeaderView:CustomHeaderView,shouldChangeBarAlpha alpha:CGFloat)}
最后就是需要一个对外开放的方法,设置之前说的相关contentView的frame实现圆滑效果以及触发Delegate方法
// MARK: - 对外接口func layoutHeaderWillScroll(offSet:CGPoint){ //获取垂直偏移量 let contentOffY = offSet.y //如果偏移量大于最大偏移量,因为是负数,所以是小于 if(contentOffY < maxContentOff) { //锁定坐标 self.delegate?.customHeaderView(self, lockScrollView: maxContentOff) } else if(contentOffY < 0)//如果小于0,表示headerView还显示在ScrollView中 { var rect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height) rect.origin.y += contentOffY ; rect.size.height -= contentOffY; self.contentView.frame = rect; } //64 + 当前的垂直偏移量 let alpha = (-originY + contentOffY) / self.frame.size.height //设置透明度 self.delegate?.customHeaderView(self, shouldChangeBarAlpha: alpha)}
在主ViewController中使用即可
定义初始化的属性以及在ViewDidLoad中进行初始化
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,CustomHeaderViewDelegate{ var tableView: UITableView! var imageView: UIImageView! var imageHeight:CGFloat? var imageDistance:CGFloat? let barColor = UIColor.orangeColor() override func viewDidLoad() { super.viewDidLoad() //设置导航栏的属性 self.navigationController?.navigationBar.setViewColor(barColor.colorWithAlphaComponent(0.0)) //设置列表属性 tableView = UITableView(frame: self.view.bounds) tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell") tableView.dataSource = self self.view.addSubview(tableView) //设置显示图片的视图 imageView = UIImageView(frame: CGRectMake(0, 0, self.view.bounds.size.width, 100)) imageView.contentMode = .ScaleAspectFill imageView.image = UIImage(named: "backGround.jpg") let customHeaderView = CustomHeaderView(subView: imageView, maxContentOff: -120, headerViewSize: CGSize(width: self.view.bounds.size.width,height: 100),delegate:self) tableView.tableHeaderView = customHeaderView }
为了不影响其他的控制器导航栏,不要忘记在消失的时候取消ScrollView的代理以及对NavigationBar图层的去除,
override func viewWillAppear(animated: Bool){ super.viewWillAppear(animated) tableView.delegate = self;}override func viewWillDisappear(animated: Bool){ tableView.delegate = nil super.viewWillDisappear(animated) self.navigationController?.navigationBar.relieveCover()}
在tableView中实现ScrollViewDidScroll:协议方法,调用headerView的对外接口即可
//MARK: - UIScrollView Delegatefunc scrollViewDidScroll(scrollView: UIScrollView){ //获得当前的自定义HeaderView对象 let customView:CustomHeaderView = (scrollView as! UITableView).tableHeaderView as! CustomHeaderView //设置滚动 customView.layoutHeaderWillScroll(scrollView.contentOffset) }
实现CustomHeaderView的代理方法
//MARK: - CustomHeaderViewDelegatefunc customHeaderView(customHeaderView: CustomHeaderView, lockScrollView maxContentOffSet: CGFloat) { //锁定滚动视图 self.tableView.contentOffset.y = maxContentOffSet}func customHeaderView(customHeaderView: CustomHeaderView, shouldChangeBarAlpha alpha:CGFloat) { //设置透明度 self.navigationController?.navigationBar.setViewColor(self.barColor.colorWithAlphaComponent(alpha))}
0 0
- iOS开发------响应TableView下拉设置NavigationBar的透明度
- IOS设置NavigationBar的颜色以及透明度
- 设置navigationBar的透明度
- IOS之UI--动态设置NavigationBar的颜色以及透明度
- IOS之UI--动态设置NavigationBar的颜色以及透明度
- iOS开发之NavigationBar的简单设置
- iOS改变Navigationbar透明度
- navigationBar随着tableview滑动透明度渐变
- iOS开发 -- 设置tableView的边框
- iOS开发之设置navigationBar的背景颜色为无色
- iOS开发-设置NavigationBar的颜色和字体属性
- iOS 设置NavigationBar的样式
- 去除iOS 7 grouped tableview与navigationBar之间的间隔
- 去除iOS 7 grouped tableview与navigationBar之间的间隔
- iOS tableview de顶部被navigationbar遮住的问题
- tableview——设置cell的文字居中和透明度
- iOS设置导航栏navigationBar大小、颜色、透明度等一切操作(WRNavigationBar)
- ios设置navigationbar.title字体的方法
- SQL Server总结(2):对数据库访问
- Openstack 03 - Nova Compute
- SVM
- Shell Zsh
- 设计模式之面向对象再回首
- iOS开发------响应TableView下拉设置NavigationBar的透明度
- Aizu 0525 Osenbei【枚举+dfs】
- 第二周项目三输出图案(b)
- 蓝桥杯 历届试题 调和级数
- Java 消息服务(JMS)
- linux 负载监控
- cocos2dx3.X项目重写(二)新的物理引擎
- HDU-3905 Sleeping
- 人工智能——电脑模拟人类学习