農林漁牧網

您現在的位置是:首頁 > 農業

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

2021-06-24由 遊戲時裝分享 發表于 農業

導航欄一般寫什麼

1. 要實現以下這些效果都非常簡單

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

2. 廢話不多說,先看看實現效果

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

3. 下面告訴你我為什麼說實現這些效果非常簡單

比如說要實現螞蟻森林的導航欄效果(有以下幾個需求):

剛進入導航欄透明、兩邊按鈕和文字都是白色、狀態列也是白色

向上滾動後導航欄背景由透明逐漸變成白色

當超過某一點後,標題變成

黑色

、狀態列變成

黑色

、兩邊按鈕變成

藍色

實現步驟:

3。1。 實現剛進入導航欄透明、兩邊按鈕和文字都是白色、狀態列也是白色

override func viewDidLoad()

{

super。viewDidLoad()

// 設定導航欄顏色為白色

navBarBarTintColor = 。white

// 設定剛進入頁面時透明度為0

navBarBackgroundAlpha = 0

}

3。2。 實現剩下兩個需求

func scrollViewDidScroll(_ scrollView: UIScrollView){ let offsetY = scrollView

。contentOffset。y

if

(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 =

。white

navBarTitleColor =

。white

statusBarStyle =

。lightContent

}}

else

{navBarBackgroundAlpha =

0

navBarTintColor =

。white

navBarTitleColor =

。white

statusBarStyle =

。lightContent

}}

3。3。 發現沒有,改變相關屬性只要一句程式碼就完全搞定了!!!

// 一行程式碼搞定導航欄顏色

navBarBarTintColor = 。white

// 一行程式碼搞定導航欄透明度

navBarBackgroundAlpha =

alpha

// 一行程式碼搞定導航欄兩邊按鈕顏色navBarTintColor = UIColor(

red

0

green

0。478431

blue

1

alpha

1。0

// 一行程式碼搞定導航欄上標題顏色

navBarTitleColor = 。black

// 一行程式碼搞定狀態列是 default 還是 lightContent

statusBarStyle = 。

default

3。4。 說了這麼多,看看幾句程式碼能否實現我們需要的效果吧

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

3。5。 有人可能會問:這只是在一個介面裡面,但是涉及到push、pop、右滑手勢怎麼辦呢?

答:沒關係,我已經給你處理好了,你不用寫一句程式碼!!!那麼看看效果吧

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

4. 好了,說了這麼多接下來看看如何實現的吧

4。1 實現導航欄透明漸變就很簡單了,網上一找一大堆,大部分都是透過加一層的方法來實現(在這裡就是加一個view到navigationBar上)

// set navigationBar barTintColor

fileprivate

func

wr_setBackgroundColor(color:UIColor)

{

if

(backgroundView ==

nil

){

// add a image(nil color) to _UIBarBackground make it clear

setBackgroundImage(

UIImage

(),

for

:。

default

)backgroundView =

UIView

(frame:

CGRect

(x:

0

,y:

0

,width:

Int

(bounds。width), height:

64

))

// _UIBarBackground is first subView for navigationBar

subviews。first?。insertSubview(backgroundView ??

UIView

(), at:

0

)} backgroundView?。backgroundColor = color}

// set _UIBarBackground alpha (_UIBarBackground subviews alpha <=>fileprivate

func

wr_setBackgroundAlpha(alpha:CGFloat)

{

let

barBackgroundView = subviews[

0

]barBackgroundView。alpha = alpha}

4。2 你以為就這樣結束了嗎,來看看下面的問題,當由透明的導航欄右滑到不透明的導航欄看看會出現什麼情況?

4。3 處理右滑返回手勢問題

我們都知道,導航欄是屬於導航控制器的,一個導航欄不可能出現兩個顏色,那麼右滑突兀怎麼解決呢?兩個方法,一個方法是自定義導航欄(後面會說),另一個方法是改變導航欄顏色,我們假設當前控制器為fromVC,返回的控制器為toVC,如果可以實現從 fromVC 右滑到 toVC 導航欄顏色漸變那麼問題就解決了!但是導航欄只有一個顏色啊~~~怎麼辦?

同樣,可以透過加一層的方法來解決。我們可以記錄一下 fromVC消失前對應的導航欄顏色 和 toVC 當前的導航欄顏色,然後根據右滑進度percentComplete,來計算漸變色,這樣問題就解決了!

記錄ViewController對應導航欄的顏色和透明度

// navigationBar barTintColorvar

navBarBarTintColor:

UIColor

{

get

{

guard

let

barTintColor = objc_getAssociatedObject(

self

,&

AssociatedKeys

。navBarBarTintColor)

as

UIColor

else

{

return

UIColor

。defaultNavBarBarTintColor }

return

barTintColor }

set

{objc_setAssociatedObject(

self

,&

AssociatedKeys

。navBarBarTintColor, newValue, 。

OBJC_ASSOCIATION_RETAIN_NONATOMIC

if

customNavBar。isKind(of:

UINavigationBar

self

){

let

navBar = customNavBar

as

UINavigationBar

navBar。wr_setBackgroundColor(color: newValue) }

else

{

if

pushToCurrentVCFinished ==

true

&& pushToNextVCFinished ==

false

{navigationController?。setNeedsNavigationBarUpdate(barTintColor: newValue) } } }}

// navigationBar _UIBarBackground alphavar

navBarBackgroundAlpha:

CGFloat

{

get

{

guard

let

barBackgroundAlpha = objc_getAssociatedObject(

self

,&

AssociatedKeys

。navBarBackgroundAlpha)

as

CGFloat

else

{

return

1。0

}

return

barBackgroundAlpha }

set

{objc_setAssociatedObject(

self

,&

AssociatedKeys

。navBarBackgroundAlpha, newValue, 。

OBJC_ASSOCIATION_RETAIN_NONATOMIC

if

customNavBar。isKind(of:

UINavigationBar

self

){

let

navBar = customNavBar

as

UINavigationBar

navBar。wr_setBackgroundAlpha(alpha: newValue) }

else

{

if

pushToCurrentVCFinished ==

true

&& pushToNextVCFinished ==

false

{navigationController?。setNeedsNavigationBarUpdate(barBackgroundAlpha: newValue) } } }}

交換系統方法 _updateInteractiveTransition(監控右滑返回手勢的進度)

// swizzling system method: _updateInteractiveTransition

func

wr_updateInteractiveTransition(

_

percentComplete: CGFloat)

{

guard

let

topViewController = topViewController,

let

coordinator = topViewController。transitionCoordinator

else

{wr_updateInteractiveTransition(percentComplete)

return

}

let

fromVC = coordinator。viewController(forKey: 。from)

let

toVC = 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(

from

Color: UIColor,

to

Color: UIColor, percent: CGFloat) -> UIColor{ // get current color RGBA var

from

Red: CGFloat =

0

var

from

Green: CGFloat =

0

var

from

Blue: CGFloat =

0

var

from

Alpha: CGFloat =

0

from

Color。getRed(&

from

Red, green: &

from

Green, blue: &

from

Blue, alpha: &

from

Alpha) // get

to

color RGBA var

to

Red: CGFloat =

0

var

to

Green: CGFloat =

0

var

to

Blue: CGFloat =

0

var

to

Alpha: CGFloat =

0

to

Color。getRed(&

to

Red, green: &

to

Green, blue: &

to

Blue, alpha: &

to

Alpha) // calculate middle color RGBA let newRed =

from

Red + (

to

Red -

from

Red) * percent let newGreen =

from

Green + (

to

Green -

from

Green) * percent let newBlue =

from

Blue + (

to

Blue -

from

Blue) * percent let newAlpha =

from

Alpha + (

to

Alpha -

from

Alpha) * percent return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: newAlpha)}

改變導航欄顏色和透明度

fileprivate func updateNavigationBar(

from

VC: UIViewController?,

to

VC: UIViewController?, progress: CGFloat){ // change navBarBarTintColor let

from

BarTintColor =

from

VC?。navBarBarTintColor ?? 。

default

NavBarBarTintColor let

to

BarTintColor =

to

VC?。navBarBarTintColor ?? 。

default

NavBarBarTintColor let newBarTintColor = UIColor。middleColor(

from

Color:

from

BarTintColor,

to

Color:

to

BarTintColor, percent: progress)

set

NeedsNavigationBarUpdate(barTintColor: newBarTintColor) // change navBarTintColor let

from

TintColor =

from

VC?。navBarTintColor ?? 。

default

NavBarTintColor let

to

TintColor =

to

VC?。navBarTintColor ?? 。

default

NavBarTintColor let newTintColor = UIColor。middleColor(

from

Color:

from

TintColor,

to

Color:

to

TintColor, percent: progress)

set

NeedsNavigationBarUpdate(tintColor: newTintColor) // change navBarTitleColor let

from

TitleColor =

from

VC?。navBarTitleColor ?? 。

default

NavBarTitleColor let

to

TitleColor =

to

VC?。navBarTitleColor ?? 。

default

NavBarTitleColor let newTitleColor = UIColor。middleColor(

from

Color:

from

TitleColor,

to

Color:

to

TitleColor, percent: progress)

set

NeedsNavigationBarUpdate(titleColor: newTitleColor) // change navBar _UIBarBackground alpha let

from

BarBackgroundAlpha =

from

VC?。navBarBackgroundAlpha ?? UIColor。

default

BackgroundAlpha let

to

BarBackgroundAlpha =

to

VC?。navBarBackgroundAlpha ?? UIColor。

default

BackgroundAlpha let newBarBackgroundAlpha = UIColor。middleAlpha(

from

Alpha:

from

BarBackgroundAlpha,

to

Alpha:

to

BarBackgroundAlpha, percent: progress)

set

NeedsNavigationBarUpdate(barBackgroundAlpha: newBarBackgroundAlpha)}

好了!來看看處理後的效果吧,是不是好多了呢~

4。4 別高興的太早,還有其他問題。在右滑返回手勢的過程中,導航欄顏色和透明度會根據手勢變化而變化。但是一旦鬆手,系統會自動完成或取消返回操作。導致透明度停留在最後的那個狀態。

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

4。5 咱們來處理右滑返回手勢中斷的問題吧~

透過遵守UINavigationBarDelegate協議,實現

optional public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool // same as push methods 方法來監聽右滑返回手勢中斷的情況

public

func

navigationBar(

_

navigationBar: UINavigationBar, shouldPop item: UINavigationItem)

->

Bool

{

if

let

topVC = topViewController,

let

coor = topVC。transitionCoordinator, coor。initiallyInteractive {

if

#available(iOS

10。0

,*) { coor。notifyWhenInteractionChanges({ (context)

in

self

。dealInteractionChanges(context) }) }

else

{coor。notifyWhenInteractionEnds({ (context)

in

self

。dealInteractionChanges(context) }) }

return

true

}

let

itemCount = navigationBar。items?。

count

??

0

let

n= viewControllers。

count

>= itemCount ?

2

1

let

popToVC = viewControllers[viewControllers。

count

-n] popToViewController(popToVC, animated:

true

return

true

}

// deal the gesture of return break offprivate

func

dealInteractionChanges(

_

context: UIViewControllerTransitionCoordinatorContext)

{

let

animations: (

UITransitionContextViewControllerKey

)-> () = {

let

curColor = context。viewController(forKey: $

0

)?。navBarBarTintColor ??

UIColor

。defaultNavBarBarTintColor

let

curAlpha = context。viewController(forKey: $

0

)?。navBarBackgroundAlpha ??

UIColor

。defaultBackgroundAlpha

self

。setNeedsNavigationBarUpdate(barTintColor: curColor)

self

。setNeedsNavigationBarUpdate(barBackgroundAlpha: curAlpha) }

// after that, cancel the gesture of return

if

context。isCancelled {

let

cancelDuration:

TimeInterval

=context。transitionDuration *

Double

(context。percentComplete)

UIView

。animate(withDuration: cancelDuration) { animations(。from) } }

else

{

// after that, finish the gesture of return

let

finishDuration:

TimeInterval

=context。transitionDuration *

Double

1

-context。percentComplete)

UIView

。animate(withDuration: finishDuration) { animations(。to) } }}

處理後:

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

4。5 同樣,push和pop也要處理一下 ~

但是push和pop我們拿不到進度怎麼辦呢?處理辦法是,透過交換方法,自己實現給push和pop新增進度。

// MARK: swizzling push

struct

pushProperties

{fileprivate

static

let

pushDuration =

0。13

fileprivate

static

var

displayCount =

0

fileprivate

static

var

pushProgress:

CGFloat

{

let

all:

CGFloat

=

CGFloat

60。0

*pushDuration)

let

current =

min

(all,

CGFloat

(displayCount))

return

current / all }}

// swizzling system method: pushViewController

func

wr_pushViewController(

_

viewController: UIViewController, animated: Bool)

{

var

displayLink:

CADisplayLink

?=

CADisplayLink

(target:

self

,selector: #selector(pushNeedDisplay)) displayLink?。add(to:

RunLoop

。main, forMode: 。defaultRunLoopMode)

CATransaction

。setCompletionBlock { displayLink?。invalidate() displayLink =

nil

pushProperties。displayCount =

0

viewController。pushToCurrentVCFinished =

true

};

CATransaction

。setAnimationDuration(pushProperties。pushDuration)

CATransaction

。begin() wr_pushViewController(viewController, animated: animated)

CATransaction

。commit()}

計算push進度,並且根據進度更新導航欄顏色和透明度

//

change

navigationBar barTintColor smooth before push

to

current VC finished

or

before

pop

to

current VC finishedfunc pushNeedDisplay(){ guard

let

topViewController = topViewController,

let

coordinator = topViewController。transitionCoordinator

else

{

return

}pushProperties。displayCount +=

1

let

pushProgress = pushProperties。pushProgress //

print

“第(pushProperties。displayCount)次push的進度:(pushProgress)”

let

fromVC = coordinator。viewController(forKey: 。from)

let

toVC = coordinator。viewController(forKey: 。

to

)updateNavigationBar(fromVC: fromVC, toVC: toVC, progres

s:

pushProgress)}

pop的設定方法也一樣,具體請檢視程式碼

4。6 以上都是改變導航欄的顏色和透明度,同樣改變導航欄的按鈕顏色和標題顏色,以及狀態列狀態都和改變顏色一樣,每個ViewController記錄一下。需要改變的時候,ViewController 改變一下屬性就ok了,非常方便!

那麼接下來看一下其他demo的動態效果圖吧~~~

新浪微博個人中心

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

qq空間

知乎日報

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

螞蟻森林

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

5. 好了,來說說前面提過的自定義導航欄吧

5。1 至於怎麼自定義導航欄我就不說了,來說說如果是自定義導航欄,那怎麼才能像之前一樣一句程式碼改變導航欄屬性。

經過封裝,自定義導航欄只需要多寫一行程式碼!!!

// 自定義導航欄必須設定這個屬性!!!!!!customNavBar = navBar

如果把這行程式碼放在基類控制器中,那麼其他所有繼承基類控制器都可以一句程式碼修改導航欄屬性~~~

看看自定義導航欄的效果吧,是不是也很棒

6. 最後看一下移動導航欄的效果

超簡單!!! iOS設定狀態列、導航欄按鈕、標題、顏色、透明度,偏移等

實現程式碼

/// 設定導航欄在垂直方向上平移多少距離

func

wr_setTranslationY(translationY:CGFloat)

{transform =

CGAffineTransform

init

(translationX:

0

,y: translationY)} ——-

到這裡就結束��,具體程式碼請前往:

——-

參考資料:

——-

歡迎關注我的微博: