ios 系统状态栏样式修改_超简单!!! iOS设置状态栏、导航栏按钮、标题、颜色、透明度,偏移等…

原标题:超简单!!! iOS设置状态栏、导航栏按钮、标题、颜色、透明度,偏移等

1. 要实现以下这些效果都非常简单

5743be5d511ba3441472a0c6452555eb.png

2. 废话不多说,先看看实现效果

de10c02777c63cffb988c6b39b68f546.png

3. 下面告诉你我为什么说实现这些效果非常简单

比如说要实现蚂蚁森林的导航栏效果(有以下几个需求):

刚进入导航栏透明、两边按钮和文字都是白色、状态栏也是白色

向上滚动后导航栏背景由透明逐渐变成白色

当超过某一点后,标题变成黑色、状态栏变成黑色、两边按钮变成蓝色

实现步骤:

3.1. 实现刚进入导航栏透明、两边按钮和文字都是白色、状态栏也是白色

override func viewDidLoad()

{

super.viewDidLoad()

// 设置导航栏颜色为白色

navBarBarTintColor = .white

// 设置刚进入页面时透明度为0

navBarBackgroundAlpha = 0

}

3.2. 实现剩下两个需求

func scrollViewDidScroll(_ scrollView: UIScrollView){ let offsetY = scrollView .contentOffset.yif(offsetY > NAVBAR_COLORCHANGE_POINT) { let alpha = (offsetY – NAVBAR_COLORCHANGE_POINT) / CGFloat(kNavBarBottom) // 向上滚动后导航栏背景由透明逐渐变成白色navBarBackgroundAlpha = alpha if(alpha > 0.5) { // 当超过某一点后,两边按钮变成蓝色navBarTintColor = UIColor(red: 0, green: 0.478431, blue: 1, alpha: 1.0) // 标题变成黑色navBarTitleColor = .black// 状态栏变成黑色statusBarStyle = .default} else{ // 当没有超过某点,上面属性还原navBarTintColor = .whitenavBarTitleColor = .whitestatusBarStyle = .lightContent} } else{ navBarBackgroundAlpha = 0navBarTintColor = .whitenavBarTitleColor = .whitestatusBarStyle = .lightContent}}

3.3. 发现没有,改变相关属性只要一句代码就完全搞定了!!!

// 一行代码搞定导航栏颜色navBarBarTintColor = .white

// 一行代码搞定导航栏透明度navBarBackgroundAlpha = alpha

// 一行代码搞定导航栏两边按钮颜色navBarTintColor = UIColor( red: 0, green: 0.478431, blue: 1, alpha: 1.0)

// 一行代码搞定导航栏上标题颜色navBarTitleColor = .black

// 一行代码搞定状态栏是 default 还是 lightContentstatusBarStyle = . default

3.4. 说了这么多,看看几句代码能否实现我们需要的效果吧

d3f04255747e7c9560eb435777bcb01f.gif

3.5. 有人可能会问:这只是在一个界面里面,但是涉及到push、pop、右滑手势怎么办呢?

答:没关系,我已经给你处理好了,你不用写一句代码!!!那么看看效果吧

920578bac42646e1651676dfb75987b2.gif

4. 好了,说了这么多接下来看看如何实现的吧

4.1 实现导航栏透明渐变就很简单了,网上一找一大堆,大部分都是通过加一层的方法来实现(在这里就是加一个view到navigationBar上)

// set navigationBar barTintColorfileprivate funcwr_setBackgroundColor(color:UIColor){ if(backgroundView == nil) { // add a image(nil color) to _UIBarBackground make it clearsetBackgroundImage( UIImage(), for: . default) backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: Int(bounds.width), height: 64)) // _UIBarBackground is first subView for navigationBarsubviews.first?.insertSubview(backgroundView ?? UIView(), at: 0) } backgroundView?.backgroundColor = color} // set _UIBarBackground alpha (_UIBarBackground subviews alpha <= _UIBarBackground alpha)fileprivate funcwr_setBackgroundAlpha(alpha:CGFloat){ letbarBackgroundView = subviews[ 0] barBackgroundView.alpha = alpha}

4.2 你以为就这样结束了吗,来看看下面的问题,当由透明的导航栏右滑到不透明的导航栏看看会出现什么情况?

4.3 处理右滑返回手势问题

我们都知道,导航栏是属于导航控制器的,一个导航栏不可能出现两个颜色,那么右滑突兀怎么解决呢?两个方法,一个方法是自定义导航栏(后面会说),另一个方法是改变导航栏颜色,我们假设当前控制器为fromVC,返回的控制器为toVC,如果可以实现从 fromVC 右滑到 toVC 导航栏颜色渐变那么问题就解决了!但是导航栏只有一个颜色啊~~~怎么办?

同样,可以通过加一层的方法来解决。我们可以记录一下 fromVC消失前对应的导航栏颜色 和 toVC 当前的导航栏颜色,然后根据右滑进度percentComplete,来计算渐变色,这样问题就解决了!

记录ViewController对应导航栏的颜色和透明度

// navigationBar barTintColorvarnavBarBarTintColor: UIColor{ get{ guardletbarTintColor = objc_getAssociatedObject( self, & AssociatedKeys.navBarBarTintColor) as? UIColorelse{ returnUIColor.defaultNavBarBarTintColor } returnbarTintColor } set{ objc_setAssociatedObject( self, & AssociatedKeys.navBarBarTintColor, newValue, . OBJC_ASSOCIATION_RETAIN_NONATOMIC) ifcustomNavBar.isKind(of: UINavigationBar. self) { letnavBar = customNavBar as! UINavigationBarnavBar.wr_setBackgroundColor(color: newValue) } else{ ifpushToCurrentVCFinished == true&& pushToNextVCFinished == false{ navigationController?.setNeedsNavigationBarUpdate(barTintColor: newValue) } } }} // navigationBar _UIBarBackground alphavarnavBarBackgroundAlpha: CGFloat{ get{ guardletbarBackgroundAlpha = objc_getAssociatedObject( self, & AssociatedKeys.navBarBackgroundAlpha) as? CGFloatelse{ return1.0} returnbarBackgroundAlpha } set{ objc_setAssociatedObject( self, & AssociatedKeys.navBarBackgroundAlpha, newValue, . OBJC_ASSOCIATION_RETAIN_NONATOMIC) ifcustomNavBar.isKind(of: UINavigationBar. self) { letnavBar = customNavBar as! UINavigationBarnavBar.wr_setBackgroundAlpha(alpha: newValue) } else{ ifpushToCurrentVCFinished == true&& pushToNextVCFinished == false{ navigationController?.setNeedsNavigationBarUpdate(barBackgroundAlpha: newValue) } } }}

交换系统方法 _updateInteractiveTransition(监控右滑返回手势的进度)

// swizzling system method: _updateInteractiveTransitionfuncwr_updateInteractiveTransition(_percentComplete: CGFloat){ guardlettopViewController = topViewController, letcoordinator = topViewController.transitionCoordinator else{ wr_updateInteractiveTransition(percentComplete) return} letfromVC = coordinator.viewController(forKey: .from) lettoVC = coordinator.viewController(forKey: .to) updateNavigationBar(fromVC: fromVC, toVC: toVC, progress: percentComplete) wr_updateInteractiveTransition(percentComplete) }

根据 fromVC 与 toVC 的导航栏颜色 配合 返回手势进度计算渐变色

// Calculate the middle Color with translation percentclass fileprivate func middleColor( fromColor: UIColor, toColor: UIColor, percent: CGFloat) -> UIColor{ // get current color RGBA var fromRed: CGFloat = 0var fromGreen: CGFloat = 0var fromBlue: CGFloat = 0var fromAlpha: CGFloat = 0fromColor.getRed(& fromRed, green: & fromGreen, blue: & fromBlue, alpha: & fromAlpha) // get tocolor RGBA var toRed: CGFloat = 0var toGreen: CGFloat = 0var toBlue: CGFloat = 0var toAlpha: CGFloat = 0toColor.getRed(& toRed, green: & toGreen, blue: & toBlue, alpha: & toAlpha) // calculate middle color RGBA let newRed = fromRed + ( toRed – fromRed) * percent let newGreen = fromGreen + ( toGreen – fromGreen) * percent let newBlue = fromBlue + ( toBlue – fromBlue) * percent let newAlpha = fromAlpha + ( toAlpha – fromAlpha) * percent return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha)}

改变导航栏颜色和透明度

fileprivate func updateNavigationBar( fromVC: UIViewController?, toVC: UIViewController?, progress: CGFloat){ // change navBarBarTintColor let fromBarTintColor = fromVC?.navBarBarTintColor ?? . defaultNavBarBarTintColor let toBarTintColor = toVC?.navBarBarTintColor ?? . defaultNavBarBarTintColor let newBarTintColor = UIColor.middleColor( fromColor: fromBarTintColor, toColor: toBarTintColor, percent: progress) setNeedsNavigationBarUpdate(barTintColor: newBarTintColor) // change navBarTintColor let fromTintColor = fromVC?.navBarTintColor ?? . defaultNavBarTintColor let toTintColor = toVC?.navBarTintColor ?? . defaultNavBarTintColor let newTintColor = UIColor.middleColor( fromColor: fromTintColor, toColor: toTintColor, percent: progress) setNeedsNavigationBarUpdate(tintColor: newTintColor) // change navBarTitleColor let fromTitleColor = fromVC?.navBarTitleColor ?? . defaultNavBarTitleColor let toTitleColor = toVC?.navBarTitleColor ?? . defaultNavBarTitleColor let newTitleColor = UIColor.middleColor( fromColor: fromTitleColor, toColor: toTitleColor, percent: progress) setNeedsNavigationBarUpdate(titleColor: newTitleColor) // change navBar _UIBarBackground alpha let fromBarBackgroundAlpha = fromVC?.navBarBackgroundAlpha ?? UIColor. defaultBackgroundAlpha let toBarBackgroundAlpha = toVC?.navBarBackgroundAlpha ?? UIColor. defaultBackgroundAlpha let newBarBackgroundAlpha = UIColor.middleAlpha( fromAlpha: fromBarBackgroundAlpha, toAlpha: toBarBackgroundAlpha, percent: progress) setNeedsNavigationBarUpdate(barBackgroundAlpha: newBarBackgroundAlpha)}

好了!来看看处理后的效果吧,是不是好多了呢~

4.4 别高兴的太早,还有其他问题。在右滑返回手势的过程中,导航栏颜色和透明度会根据手势变化而变化。但是一旦松手,系统会自动完成或取消返回操作。导致透明度停留在最后的那个状态。

fcd52cd4f3029d87508d08d9e1342079.gif

4.5 咱们来处理右滑返回手势中断的问题吧~

通过遵守UINavigationBarDelegate协议,实现

optional public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool // same as push methods 方法来监听右滑返回手势中断的情况

publicfuncnavigationBar(_navigationBar: UINavigationBar, shouldPop item: UINavigationItem)-> Bool{ iflettopVC = topViewController, letcoor = topVC.transitionCoordinator, coor.initiallyInteractive { if#available(iOS 10.0, *) { coor.notifyWhenInteractionChanges({ (context) inself.dealInteractionChanges(context) }) } else{ coor.notifyWhenInteractionEnds({ (context) inself.dealInteractionChanges(context) }) } returntrue} letitemCount = navigationBar.items?. count?? 0letn = viewControllers. count>= itemCount ? 2: 1letpopToVC = viewControllers[viewControllers. count- n] popToViewController(popToVC, animated: true) returntrue} // deal the gesture of return break offprivatefuncdealInteractionChanges(_context: UIViewControllerTransitionCoordinatorContext){ letanimations: ( UITransitionContextViewControllerKey) -> () = { letcurColor = context.viewController(forKey: $ 0)?.navBarBarTintColor ?? UIColor.defaultNavBarBarTintColor letcurAlpha = context.viewController(forKey: $ 0)?.navBarBackgroundAlpha ?? UIColor.defaultBackgroundAlpha self.setNeedsNavigationBarUpdate(barTintColor: curColor) self.setNeedsNavigationBarUpdate(barBackgroundAlpha: curAlpha) } // after that, cancel the gesture of returnifcontext.isCancelled { letcancelDuration: TimeInterval= context.transitionDuration * Double(context.percentComplete) UIView.animate(withDuration: cancelDuration) { animations(.from) } } else{ // after that, finish the gesture of returnletfinishDuration: TimeInterval= context.transitionDuration * Double( 1- context.percentComplete) UIView.animate(withDuration: finishDuration) { animations(.to) } }}

处理后:

6db811a35ba72258c44b034fe50480b8.gif

4.5 同样,push和pop也要处理一下 ~

但是push和pop我们拿不到进度怎么办呢?处理办法是,通过交换方法,自己实现给push和pop添加进度。

// MARK: swizzling pushstructpushProperties{ fileprivate staticletpushDuration = 0.13fileprivate staticvardisplayCount = 0fileprivate staticvarpushProgress: CGFloat{ letall: CGFloat= CGFloat( 60.0* pushDuration) letcurrent = min(all, CGFloat(displayCount)) returncurrent / all }} // swizzling system method: pushViewControllerfuncwr_pushViewController(_viewController: UIViewController, animated: Bool){ vardisplayLink: CADisplayLink? = CADisplayLink(target: self, selector: #selector(pushNeedDisplay)) displayLink?.add(to: RunLoop.main, forMode: .defaultRunLoopMode) CATransaction.setCompletionBlock { displayLink?.invalidate() displayLink = nilpushProperties.displayCount = 0viewController.pushToCurrentVCFinished = true}; CATransaction.setAnimationDuration(pushProperties.pushDuration) CATransaction.begin() wr_pushViewController(viewController, animated: animated) CATransaction.commit()}

计算push进度,并且根据进度更新导航栏颜色和透明度

// changenavigationBar barTintColor smooth before push tocurrent VC finished orbefore poptocurrent VC finishedfunc pushNeedDisplay(){ guard lettopViewController = topViewController, letcoordinator = topViewController.transitionCoordinator else{ return} pushProperties.displayCount += 1letpushProgress = pushProperties.pushProgress // print( "第(pushProperties.displayCount)次push的进度:(pushProgress)") letfromVC = coordinator.viewController(forKey: .from) lettoVC = coordinator.viewController(forKey: . to) updateNavigationBar(fromVC: fromVC, toVC: toVC, progres s:pushProgress)}

pop的设置方法也一样,具体请查看代码

4.6 以上都是改变导航栏的颜色和透明度,同样改变导航栏的按钮颜色和标题颜色,以及状态栏状态都和改变颜色一样,每个ViewController记录一下。需要改变的时候,ViewController 改变一下属性就ok了,非常方便!

那么接下来看一下其他demo的动态效果图吧~~~

新浪微博个人中心

89985dbeb7105f07c55d5e70e6ecdf66.gif

qq空间

知乎日报

0c16515ca0993d982610bf68ad2dcbd7.gif

蚂蚁森林

c11dd706d04d104233b57f527eb0c084.gif

5. 好了,来说说前面提过的自定义导航栏吧

5.1 至于怎么自定义导航栏我就不说了,来说说如果是自定义导航栏,那怎么才能像之前一样一句代码改变导航栏属性。

经过封装,自定义导航栏只需要多写一行代码!!!

// 自定义导航栏必须设置这个属性!!!!!!customNavBar = navBar

如果把这行代码放在基类控制器中,那么其他所有继承基类控制器都可以一句代码修改导航栏属性~~~

看看自定义导航栏的效果吧,是不是也很棒

6. 最后看一下移动导航栏的效果

bef821387184a9ee834e29a0564bbcbc.gif

实现代码

/// 设置导航栏在垂直方向上平移多少距离funcwr_setTranslationY(translationY:CGFloat){ transform = CGAffineTransform. init(translationX: 0, y: translationY)} —

到这里就结束��,具体代码请前往:

参考资料:

欢迎关注我的微博:返回搜狐,查看更多

责任编辑:

Published by

风君子

独自遨游何稽首 揭天掀地慰生平