分享我所知道的实现navigationBar渐变的几种方法
一直有用到实现navigationBar渐变的效果, 这里就分享一下几种大家可能会尝试的不可行的方法和几种可行的方法Demo地址
最终效果.gif
首先我们来看看一些navigationBar的属性
//这个属性设置是否半透明效果, 如果设置为NO, 则内容可能会向下偏移64
public var translucent: Bool // Default is NO on iOS 6 and earlier. Always YES if barStyle is set to UIBarStyleBlackTranslucent
// 这个属性是设置navigationBar上面的barButtonItem上的文字颜色
public var tintColor: UIColor!
// 这个属性是设置navigationBar的"背景色"
public var barTintColor: UIColor? // default is nil
// 这个方法设置背景图片
public func setBackgroundImage(backgroundImage: UIImage?, forBarPosition barPosition: UIBarPosition, barMetrics: UIBarMetrics)
// 这个属性设置阴影图片
public var shadowImage: UIImage?
需要注意的是当上面的属性设置不同值的时候navigationBar的层级结构是不一样的, 这个会在后面的方法中提到 比如:
-
设置translucent==false的时候, navigationBar视图层级是这样的, 设置的barTintColor居然跑到了后面的红色view上面来了
translucent
-
设置translucent==true的时候, navigationBar视图层级是这样的, 设置的barTintColor在navigationBar的层级上显示
translucent.png
首先我们监控页面中的scrollView(tableView, collectionView...)的滚动, 在里面动态的设置alpha值, 我这里的设置如下
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
// 这里面改变的程度和什么时候改变, 你可以根据自己的项目需要自己设置
if offsetY <= 0 {
let alpha = offsetY / -64.0
setNavAlpha(alpha)
} else {
setNavAlpha(0.0)
}
}
// 这里面设置navigationBar的alpha
func setNavAlpha(alpha: CGFloat) {
}
}
1. 最容易想到的方法, 要实现渐变, 直接设置它的alpha应该就可以了
- 首先在viewDidLoad()里设置navigationBar的"背景色"
navigationController?.navigationBar.barTintColor = UIColor.redColor()
设置barTintColor后navigationBar的层次是这样的, 可以看到里面有很多层的view还有UIImageView(其中有用来设置barTintColor, backgroudImage, 实现半透明的view...)
barTintColor.png- 设置navigationBar.alpha
func setNavAlpha(alpha: CGFloat) {
navigationController?.navigationBar.alpha = alpha
}
这样处理的效果如下
alpha.gif可以看到navigationBar确实能够渐变, 效果很好, 但是
这个需要注意的是, 设置view的alpha的时候, 他也会有改变这个view上的所有的子控件的alpha的效果, 所以上面的title和左右的按钮都跟着一起渐变, 我希望的是只有navigationBar的"背景色"渐变, 其他的仍然显示在上面, 所以这种一定程度上不能满足要求
2.动态改变barTintColor的alpha或者backgroundColor
func setNavAlpha(alpha: CGFloat) {
navigationController?.navigationBar.barTintColor = UIColor(red: 223.0/255.0, green: 223.0/255.0, blue: 223.0/255.0, alpha: alpha)
}
动态改变barTintColor的alpha是没有效果的, 具体的原因不清楚, 不过如果重新设置barTintColor 是有贵改变颜色的
3. 设置背景图片, 动态改变背景图片的透明度来实现
设置背景图片后的navigationBar的层级结构
image.png
可以看到已经少了两层了, 只剩三层
- 通过一个颜色获得一张图片的方法如下, 涉及一点点绘图知识
func drawImageFromColor(color: UIColor, size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.set()
UIRectFill(CGRect(origin: CGPointZero, size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
- viewDidLoad()中设置背景色
//背景色
let image = drawImageFromColor(UIColor.redColor().colorWithAlphaComponent(1.0), size: CGSize(width: view.bounds.width, height: 64.0))
navigationController?.navigationBar.setBackgroundImage(image, forBarMetrics: .Default)
- 动态改变背景图片
func setNavAlpha(alpha: CGFloat) {
let image = drawImageFromColor(UIColor.redColor().colorWithAlphaComponent(alpha), size: CGSize(width: view.bounds.width, height: 64.0))
navigationController?.navigationBar.setBackgroundImage(image, forBarMetrics: .Default)
}
这样处理后的效果是这样的
image.gif渐变的效果确实是实现了我们想要的了, 但是可以看到, 其中还有一条线是我们不想要的, 这里通过如下的设置可以去掉这条线, 然后效果就很好了
navigationController?.navigationBar.shadowImage = UIImage()
4. 直接修改navigationBar的第一层subview的alpha
- viewDidLoad()中设置颜色
navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.barTintColor = UIColor.redColor()
- 动态修改alpha
func setNavAlpha(alpha: CGFloat) {
navigationController?.navigationBar.subviews.first?.alpha = alpha
}
5. 添加一个自定义的view到navigationBar最底部, 动态改变这个view的alpha来实现
- 在viewDidLoad()里面添加view
navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
navigationController?.navigationBar.shadowImage = UIImage()
//
let test = UIView(frame: CGRect(x: 0.0, y: -20.0, width: UIScreen.mainScreen().bounds.size.width, height: 64.0))
test.backgroundColor = UIColor.redColor()
navigationController?.navigationBar.insertSubview(test, atIndex: 0)
- 动态改变这个View的alpha, 因为navigationBar上的title等其他控件不在这个view上, 所以改变他的alpha不会影响其他的控件
func setNavAlpha(alpha: CGFloat) {
navigationController?.navigationBar.subviews.first?.alpha = alpha
}
这样设置后效果也是我们想要的了
6. 在5.的基础上修改一下, 在UINavigationController分类中使用运行时添加一个属性alphaView, 然后添加一个方法来设置他的alpha
- extension如下
var alphaViewKey = "alphaViewKey"
extension UINavigationController {
var zj_alphaView: UIView? {
set {
objc_setAssociatedObject(self, &alphaViewKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &alphaViewKey) as? UIView
}
}
func zj_setBackgroundColor(color: UIColor, alpha: CGFloat) {
if zj_alphaView == nil {
zj_alphaView = UIView(frame: CGRect(x: 0.0, y: -20.0, width: UIScreen.mainScreen().bounds.width, height: 64.0))
navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
navigationBar.shadowImage = UIImage()
navigationBar.insertSubview(zj_alphaView!, atIndex: 0)
}
zj_alphaView?.backgroundColor = color.colorWithAlphaComponent(alpha)
}
}
- 使用
func setNavAlpha(alpha: CGFloat) {
navigationController?.zj_setBackgroundColor(UIColor.redColor(), alpha: alpha)
}
7.隐藏或者将navigationBar直接设置为完全透明的, 然后自己添加一个view到顶部来当作navigationBar, 这种方式比较简单实现(不少人也是这儿干的), 但是很多系统的过渡动画就没有了, 大家可以自己试试
注意, 以上各种有效的方法设置后一定要记得, 在退出当前Vc的时候将navigationBar的状态回复为原来的, 避免影响其他的界面的效果
最后提供Demo地址,如果你觉得有帮助,不妨给个star, 也可以看看里面其他的东西, 欢迎关注