iOS系統(tǒng)導航欄自定義標題動畫跳變解析

如果我們使用iOS系統(tǒng)的導航欄庸疾,自己設置titleView,leftItem和rightItem,當titleView長度達到一定時业踢,push會出現titleView左右跳變的情況,本文將分析跳變原因及解決辦法礁扮。

導航欄的內部布局

在一個全新的APP知举,自定義導航欄的左中右后瞬沦,查看布局,會發(fā)現雇锡,導航欄內部布局如下

在這里插入圖片描述

設置了自定義leftItem逛钻,titleView和rightItem,在導航欄中锰提,我們自定義的view都會被_UITAMICAdaptorView包裹曙痘,其中l(wèi)eftItem和rightItem在_UITAMICAdaptorView外還會包裹一層_UIButtonBarStackView,最后布局在_UINavigationBarContentView中立肘。

在導航欄內部布局的左邊塊边坤、中間塊和右邊塊,以下簡稱ABC谅年,整個屏幕寬為Width茧痒。

以下以iPhone XS Max為例,gap1為20踢故,gap2為6文黎。

安全區(qū)域

A不論寬度如何(包括為0),一定會距離左邊gap1殿较。

C不論寬度如何(包括為0)耸峭,一定會距離右邊gap1。

B就算再寬淋纲,也一定會距離A和C各gap2劳闹。

在這里插入圖片描述

(A設置寬40,B設置寬414洽瞬,C設置寬40)

當A和C寬度設為0時本涕,B距離屏幕左右各(gap1+gap2)。

在這里插入圖片描述

當A和C設置為nil時伙窃,B距離屏幕左右各12(gap3)菩颖。

在這里插入圖片描述

對齊方式

當增加A的寬度時,A是以左邊不動为障,右邊增加來加寬的晦闰,B的寬度會因A寬度增加而壓縮,A最寬不超過C.left-gap2*2鳍怨。

在這里插入圖片描述

當增加C的寬度時呻右,C是以右邊不動,左邊增加來加寬的鞋喇,B的寬度會因C寬度增加而壓縮声滥,C最寬不超過A.right-gap2*2。

在這里插入圖片描述

當調節(jié)B的寬度時侦香,B默認是以導航欄中心為錨點落塑,左右同時增加纽疟,且最大不會超過 162(Width-A.width-B.width-gap12-gap22)

在這里插入圖片描述

當把ABC全部調成屏幕寬時,B會被完全擠沒芜赌,AC平分除了安全區(qū)域的所有空間(Width-gap12-gap22)

在這里插入圖片描述

導航欄標題欄動畫

從左到右的跳變的產生

首先理解了前面的布局仰挣,可知道B的x坐標的相對于A的計算公式

B.left = Max( (Width - B.width)/2 , A.right+gap2)

B的x坐標理想情況下是(Width - B.width)/2,也就是動畫結束位置缠沈,實際x坐標位置可能是(Width - B.width)/2或者(A.right+gap2)(兩者取最大值),也就是最后布局位置错蝴。

當實際位置為A.right+gap2時洲愤,說明動畫初始位置在實際位置左邊,就會出現push時顷锰,導航欄title左側有個從左到右的跳變柬赐。

在這里插入圖片描述

從右到左的跳變的產生

同理,B的right坐標的相對于C的計算公式

B.right = Min( (Width + B.width)/2 , C.left-gap2)

B的right坐標理想情況下是 (Width + B.width)/2官紫,也就是動畫結束位置肛宋,實際位置可能是(Width + B.width)/2或者(C.left-gap2)(兩者取最小值),也就是最后布局位置束世。

當實際位置為(C.left-gap2)時酝陈,說明動畫初始位置在實際位置右邊,就會出現push時毁涉,導航欄title右側有個從右到左的跳變沉帮。

在這里插入圖片描述

防止跳變的結論

為了防止上述兩種跳變,只要令B的left實際位置為 (Width - B.width)/2贫堰,B的right實際位置為 (Width + B.width)/2穆壕,也就是

求 (Width - B.width)/2 > (A.right+gap2) 且 (Width + B.width)/2 < C.left-gap2 的 B.width的取值范圍?
因已知 A.right = gap1 + A.width + gap2其屏,且 C.left = Width - gap2 - C.width - gap1
可求得B的寬度限制為
B.width < Width - gap12 - gap22 - A.width2 且 B.width < Width - gap12 - gap22 - C.width2
也就是 B.width < Width - gap12 - gap22 - Max(A.width, C.width)*2

翻譯成中文就是B的寬度不能超過屏幕寬減去固定的安全區(qū)域再減去A和C之中最寬的2倍喇勋。

解決了?

不偎行,還沒完川背,到目前這步,是手Q8.0.0之前的做法睦优,設定了A和C可能存在的最大寬度(因為AC的寬度是可能會變的渗常,比如左邊沒有未讀消息和有99條未讀寬度是不一樣的,再比如右邊可能有一個圖標或兩個圖標)汗盘,然后得到的B的寬度就很窄了皱碘。

如圖,B和A之間還有一大段距離沒有利用上隐孽,如果想利用上這段空間癌椿,又不希望出現跳變健蕊,該怎么辦呢?

推翻從右到左的跳變

首先要再回到導航欄標題欄動畫 - 從右到左的跳變的產生踢俄,其實因為系統(tǒng)動畫本身就是從右到左缩功,所以看不出來有跳變,會令人以為是正常的動畫都办,以下兩張圖嫡锌,就動畫而言,不會令人有跳變的感覺琳钉。

在這里插入圖片描述

在這里插入圖片描述

會有跳變的感覺是因為加上內容后势木,B的內容從C中滑過

在這里插入圖片描述

在這里插入圖片描述

但一般情況下,C放置的都是圖標歌懒,空白區(qū)域很大啦桌,B的內容從C有動畫滑過其實可以接受。

如果可以接受及皂,那么B的寬度就變?yōu)榱酥灰蕾嘇的寬度

B.width < Width - gap12 - gap22 - A.width*2

不接受“推翻從右到左的跳變”

不行甫男,追求完美的人說,我就是這么一點點跳變都不能接受验烧,而且板驳,上面的方法只解決了C大于A的情況,A大于C的情況還是有問題呀噪窘!

好笋庄,下面重點介紹下planB——

內容越界方案

首先,ABC里的內容倔监,是可以超過ABC的寬度限制顯示的V鄙啊(后面ABC的內容各稱為abc)

什么意思呢,回到上一張圖浩习,當我把A的內容“< left”的x坐標設為-20静暂,a就頂著屏幕左邊出現了。

如果我把ABC寬度都調為0谱秽,再看內容的顯示:


在這里插入圖片描述

可以看到除了a的x坐標被我設了-20洽蛀,b和c都是以B和C的x坐標為原點顯示的,并且是全部顯示疟赊,不會因為寬度為0就不顯示郊供,也就是結論:ABC內容的顯示不會被其寬度影響,但是會位置會受ABC的x坐標的影響近哟。(當然前提你自己不能給自定義的view設置clipsToBounds為真)

也就是說驮审,在"防止跳變的結論"基礎上,我們可以把b的位置根據AC寬度進行調整,如下圖

在這里插入圖片描述

C比A寬疯淫,B和A之間空余了X的寬度(X.width = C.width - A.width)地来,那么b的x起始點位置就可以計算為 -X.width(也就是A.width - C.width),b的最大寬度為Width - A.width - C.width - gap12 - gap22熙掺;

在這里插入圖片描述

同理假如A比C寬未斑,B和C之間就空余了X的寬度(X.width = A.width - C.width),那么b的x坐標為0币绩,b的寬度為Width - A.width - C.width - gap12 - gap22蜡秽。

在這里插入圖片描述

綜上,計算b的公式為

b.left = Min(0, A.width - C.width)
b.width = Width - A.width - C.width - gap12 - gap22

當B的背景顏色置為透明時类浪,看效果就只看到B的內容了(以下兩圖區(qū)別在于右圖B背景設為透明)

在這里插入圖片描述

在這里插入圖片描述

(PS.由實踐看出载城,當a的x坐標處于安全區(qū)域gap1內時,push動畫會有一個該區(qū)域從無到有的變化费就,同理當c的right位置處于最右邊的安全區(qū)域也有,所以建議A和C的內容不要越過安全區(qū)域川队,但是這個也是有解決辦法的力细,以后再說。)

基于以上方案固额,也可以一開始就把B的寬度設為0眠蚂,然后每次只需要計算b的坐標和寬度就行了,還可以通過計算令B把左右gap2的區(qū)域也占掉斗躏。

在手Q上的實踐效果:左圖長標題逝慧,右圖短標題(左邊的未讀消息數從無到有)

在這里插入圖片描述

在這里插入圖片描述

附:不同機型下gap1和gap2的值

新增gap3(當A和C設為nil,B距離屏幕左右距離)


在這里插入圖片描述

綜上啄糙,可以判斷

if (SCREEN_WIDTH > 375) {
    gap1 = 20;
    gap3 = 12
} else {
    gap1 = 16;
    gap3 = 8;
}
    gap2 = 6;

Demo源碼:https://github.com/Xieyupeng520/AZNavigationBar/tree/master
如果有幫助到你笛臣,請給我Github上一個Star鼓勵一下O(∩_∩)O謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末隧饼,一起剝皮案震驚了整個濱河市沈堡,隨后出現的幾起案子,更是在濱河造成了極大的恐慌燕雁,老刑警劉巖诞丽,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異拐格,居然都是意外死亡僧免,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門捏浊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來懂衩,“玉大人,你說我怎么就攤上這事〔眨” “怎么了谒所?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沛申。 經常有香客問我劣领,道長,這世上最難降的妖魔是什么铁材? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任尖淘,我火速辦了婚禮,結果婚禮上著觉,老公的妹妹穿的比我還像新娘村生。我一直安慰自己,他們只是感情好饼丘,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布趁桃。 她就那樣靜靜地躺著,像睡著了一般肄鸽。 火紅的嫁衣襯著肌膚如雪卫病。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天典徘,我揣著相機與錄音蟀苛,去河邊找鬼。 笑死逮诲,一個胖子當著我的面吹牛帜平,可吹牛的內容都是我干的。 我是一名探鬼主播梅鹦,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼裆甩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帘瞭?” 一聲冷哼從身側響起淑掌,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝶念,沒想到半個月后抛腕,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡媒殉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年担敌,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廷蓉。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡全封,死狀恐怖马昙,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情刹悴,我是刑警寧澤行楞,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站土匀,受9級特大地震影響子房,放射性物質發(fā)生泄漏。R本人自食惡果不足惜就轧,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一证杭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妒御,春花似錦解愤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至惋啃,卻和暖如春李茫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肥橙。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秸侣,地道東北人存筏。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像味榛,于是被迫代替她去往敵國和親椭坚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354