激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - IOS - iOS 11 safeArea詳解及iphoneX 適配

iOS 11 safeArea詳解及iphoneX 適配

2021-04-21 19:33fruitymoon IOS

本篇文章主要介紹了iOS 11 safeArea詳解及iphoneX 適配,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

最近看了許多iphone x適配的文章,發現很少有介紹safearea的,就來隨便寫寫

現在對于iphone x的適配,有一種常見的做法是給導航欄或tabbar增加一個固定的距離,比如頂部增加44pt,底部增加34pt。這種寫死距離的做法乍看上去挺簡單,其實并不好,理由如下

  1. 不適合多機型的適配,如果以后出了一種帶劉海的ipad,需要預留出來的距離就未必是現在寫死的距離

  2. 不適合需要支持橫豎屏的app,橫屏頂部不需要增加距離,反而是左右各有44pt,底部的距離也和豎屏不同

  3. 不夠動態。還是舉個例子,假如有電話打進來了,導航欄應該會下移,這時候view可能還是會被擋住

這里我想探討一下如何使用safearealayoutguide和safeareainsets,以一種動態的方式,一勞永逸地解決iphone x甚至后續所有機型的適配問題。

safearealayoutguide

首先我們看看什么是safearealayoutguide

iOS 11 safeArea詳解及iphoneX 適配

看起來復雜,其實很簡單,我歸納一下有幾點:

  1. 它是uiview的一個只讀屬性,意味著所有uiview對象都有并且是系統幫我們創建好的

  2. 它繼承uilayoutguide,有layoutframe意味著它能代表一塊區域

  3. 它代表的區域避開了諸如導航欄、tabbar或者其他有可能擋住你這個uiview對象顯示的所有父view,意味著你的view對象只要相對另一個view的safelayoutguide做布局就不用擔心她被奇奇怪怪的東西擋住

  4. 對于控制器的view的safearealayoutguide,他的區域同樣避開了statusbar或其他有可能擋住view顯示的東西,我們甚至可以用控制器的additionalsafeareainsets屬性,來額外指定inset

  5. 如果view完全在父view的安全區域內,或者view不在視圖層級或屏幕上,那么view的safearealayoutguide區域其實和view自身是一樣大的

safearealayoutguide是一個相對抽象的概念,為了便于理解,我們可以把safearealayoutguide看成是一個“view”,這個“view”系統自動幫我們調整它的bounds,讓它不會被各種奇奇怪怪的東西擋住,包括iphone x的劉海區域和底部的一道杠區域,可以認為在這個“view”上一定能完整顯示所有內容。

以下綠色部分就是當前控制器view的safearealayoutguide區域

iOS 11 safeArea詳解及iphoneX 適配

iphone x豎屏safearealayoutguide的bounds.png

iOS 11 safeArea詳解及iphoneX 適配

iphone x橫屏safearealayoutguide的bounds.png

截圖來自https://developer.apple.com/videos/play/fall2017/801/

不過需要銘記的一點是這個“view”并不會顯示在我們的視圖層級上。
uilayoutguides will not show up in the view hierarchy, but may be used as items in an nslayoutconstraint and represent a rectangle in the layout engine.

在我看來,他最大的作用是作為參照物,讓view可以相對某個view的safearealayoutguide做布局,從而保證view能正常、安全地顯示(相對的那個view不一定要是父view)

在一種常見的使用場景里,以前我的某個view是相對于控制器的view做布局,現在是相對控制器view的safearealayoutguide做布局了

以前是這樣寫
[nslayoutconstraint constraintwithitem:someview attribute:nslayoutattributetop relatedby:nslayoutrelationequal toitem:self.vc.view attribute:nslayoutattributetop multiplier:1.0 constant:0];

現在是這樣
[nslayoutconstraint constraintwithitem:someview attribute:nslayoutattributetop relatedby:nslayoutrelationequal toitem:self.vc.view.safearealayoutguide attribute:nslayoutattributetop multiplier:1.0 constant:0];

適配前后的效果

iOS 11 safeArea詳解及iphoneX 適配

適配前.png

iOS 11 safeArea詳解及iphoneX 適配

改成相對于view的safearealayoutguide后-豎屏.png

iOS 11 safeArea詳解及iphoneX 適配

改成相對于view的safearealayoutguide后-橫屏.png

可以看到,相同的布局下,橫屏在沒有statusbar時,距離頂部是0,左邊是44,如果有statusbar,距離頂部就是20。反正不管怎么弄,只要我們相對safearealayoutguide做布局,我們的view就能夠安全完整地顯示出來

那么非ios11怎么辦?

非ios11 還是只能對view做布局,就要寫兩套布局代碼,稍后會介紹

這樣是不是就足夠應對所有情況了呢?

并不是

我們自定義的view有一邊需要緊挨著屏幕邊緣,比如我項目里是自定義的導航欄,它的頂部是挨著屏幕頂部的,那么導航欄就不能相對view的safearealayoutguide布局,否則頂部會空出來一截子

frame布局

這時就輪到safeareainsets來發揮作用啦

safeareainsets

先看一下safeareainsets的官方解釋

iOS 11 safeArea詳解及iphoneX 適配

有沒有覺得和safearealayoutguide很像?safearealayoutguide可能就是根據safeareainsets來調整自己的bounds的

iphone x豎屏時占滿整個屏幕的控制器的view的safeareainsets是(44,0,34,0),橫屏是(0,44,21,44),inset后的區域正好是safearealayoutguide區域

既然如此,對于自定義的頂部導航欄來說,我們可以給導航欄的高度加上一個vc.view.safeareainsets.top,讓他變高一點就可以了,這樣在x上,豎屏時top = 44, 橫屏時top = 0,導航欄的高度能響應改變

需要注意的是,無論safearealayoutguide還是safeareainsets都是ios11才能使用的。
對于safeareainsets,我們可以把版本判斷寫在一個函數里

我們可以這樣寫

?
1
2
3
4
5
6
static inline uiedgeinsets sgm_safeareainset(uiview *view) {
 if (@available(ios 11.0, *)) {
  return view.safeareainsets;
 }
 return uiedgeinsetszero;
}
?
1
2
3
uiedgeinsets safeareainsets = sgm_safeareainset(self.view);
cgfloat height = kdefaulttopviewheight; // 導航欄原本的高度,通常是44.0
height += safeareainsets.top > 0 ? safeareainsets.top : 20.0; // 20.0是statusbar的高度

問題又來了,這段代碼放在什么地方合適呢?前面官方文檔提到過,如果view不在屏幕上或顯示層級里,view的safeareainsets = uiedgeinsetszero,所以我們需要明確知道safeareainsets改變的時機

實際上系統已經提供了回調

對于uiviewcontroller

 

復制代碼 代碼如下:

-(void)viewsafeareainsetsdidchange ns_requires_super api_available(ios(11.0), tvos(11.0));

 

對于uiview

?
1
-(void)safeareainsetsdidchange api_available(ios(11.0),tvos(11.0));

這里主要探討controller的回調,view的回調是類似的。只要controller的view的safeareainsets改變,系統就會調用viewsafeareainsetsdidchange。自然而然,我們會想把以上代碼放在這里,然而這里有個大坑,你會發現,當這個控制器以動畫的方式push進來時,導航欄的高度也會動畫地變高,產生了不必要的多余動畫,這種體驗很糟糕

那么究竟應該放在哪里?我們很有必要看一下新的viewcontroller調用時序

以下是從“rootvc” push 到 “pushvc”控制臺輸出的調用時序以及對應控制器的view的safeareainsets

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2017-10-04 16:59:59.594811+0800 xxx[15662:803767] begin pushviewcontroller to [<_ttcc8xxxtests27containerviewcontrollertest20mockuiviewcontroller: 0x7f9c07b643b0>]
viewdidload()---optional("pushvc")---uiedgeinsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
willmove(toparentviewcontroller:)---optional("pushvc")---uiedgeinsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
viewwilldisappear---optional("rootvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewwillappear---optional("pushvc")---uiedgeinsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
viewsafeareainsetsdidchange()---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewwilllayoutsubviews()---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewdidlayoutsubviews()---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewwilllayoutsubviews()---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewdidlayoutsubviews()---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewdidappear---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
viewdiddisappear---optional("rootvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
didmove(toparentviewcontroller:)---optional("pushvc")---uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
2017-10-04 16:59:59.604563+0800 xxx[15662:803767] did pushviewcontroller [<_ttcc8xxxtests27containerviewcontrollertest20mockuiviewcontroller: 0x7f9c0790d170>]->[<_ttcc8xxxtests27containerviewcontrollertest20mockuiviewcontroller: 0x7f9c07b643b0>] time = [0.009772]

可以看到,viewsafeareainsetsdidchange調用時機很早,在viewwillappear后,這是為什么出現多余動畫的原因。并且“pushvc”的safeareainsets直到viewsafeareainsetsdidchange調用前,都是uiedgeinsetszero,之后才是正確的uiedgeinsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)

并且viewsafeareainsetsdidchange后面會調用兩次viewdidlayoutsubviews,所以我們應該把改變高度或布局的代碼都寫在viewdidlayoutsubviews里,這樣就不會有多余的動畫效果了。需要注意viewdidlayoutsubviews可能會由別的操作頻繁觸發,所以如果調整safearea布局的代碼比較耗時,可以考慮加上一個狀態標記,只在didchange后執行一次布局調整

最后的代碼應該長這樣

?
1
2
3
4
5
6
7
8
- (void)viewdidlayoutsubviews {
 [super viewdidlayoutsubviews];
 uiedgeinsets safeareainsets = sgm_safeareainset(self.view);
 cgfloat height = 44.0; // 導航欄原本的高度,通常是44.0
 height += safeareainsets.top > 0 ? safeareainsets.top : 20.0; // 20.0是statusbar的高度,這里假設statusbar不消失
 if (_navigationbar && _navigationbar.height != height) {
  _navigationbar.height = height;
 }

適配前后的效果

iOS 11 safeArea詳解及iphoneX 適配

適配前

iOS 11 safeArea詳解及iphoneX 適配

適配后

這樣對于frame布局和autolayout布局的各種情況,有了一個動態的適配方案,就是分別使用safearealayoutguide和safeareainsets來靈活處理布局,相比寫死一個固定距離,當前和未來的各種機型都能一套代碼適配,擴展性更好。我們項目目前也是采用這種做法,如果你的項目需要適配橫豎屏或ui控件布局相對復雜,真的應該考慮使用safearea

順便提一下,vfl似乎已經廢了,因為|只能表示父view的邊緣,并沒有一個符號來表示父view的safearealayoutguide的邊緣,以前我們寫的vfl代碼,好多得改,改起來也特別麻煩,建議別再用vfl了

最后一個版本判斷的問題,safeareainsets和safearealayoutguide都是ios11的api,如果不做封裝,直接在代碼里寫,勢必會出現大量@available這種版本判斷語句,代碼里到處是@available,看起來很崩潰,破壞代碼可讀性。

因為我之前寫了一個自動布局框架,這次就將safearealayoutguide和版本判斷都順便封裝在里面了,個人覺得這套框架比nslayoutanchor好用,主要作用是簡化布局代碼書寫,以下是生成一個nslayoutconstraint的對比

?
1
2
3
4
5
6
7
8
9
10
// 需求是topleftview的top等于self.view的safearealayoutguide的top
// 使用系統api
if (@available(ios 11.0, *)) {
  [nslayoutconstraint constraintwithitem:self.topleftview attribute:nslayoutattributetop relatedby:nslayoutrelationequal toitem:self.view.safearealayoutguide attribute:nslayoutattributetop multiplier:1.0 constant:0];
 } else {
  [nslayoutconstraint constraintwithitem:self.topleftview attribute:nslayoutattributetop relatedby:nslayoutrelationequal toitem:self.view attribute:nslayoutattributetop multiplier:1.0 constant:0];
 }
 
// 使用nslayoutconstraint-sslayout
self.topleftview.top_attr = self.view.top_attr_safe

在業務代碼里不會出現任何版本判斷,大家有興趣的話可以試一下

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/1432a94ef66f

延伸 · 閱讀

精彩推薦
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111312021-03-15
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5282021-01-16
主站蜘蛛池模板: 369看片你懂的小视频在线观看 | 国产精品成人免费一区久久羞羞 | 国产精品久久久久久久久久久天堂 | 成人羞羞在线观看网站 | 久久久久久久久日本理论电影 | 国产精品视频一区二区噜噜 | 精品国产乱码一区二区 | 一级大片一级一大片 | 国产女同疯狂激烈互摸 | 91重口视频 | 黄色免费大片 | h视频免费观看 | 毛片免费视频 | 2019中文字幕在线播放 | 秋霞a级毛片在线看 | 欧美国产精品一区二区 | 亚洲第一综合色 | 美女扒开腿让男生桶爽网站 | 看黄在线 | 久久久久99999 | 久久精品亚洲欧美日韩精品中文字幕 | www.99久久久 | 国产精品99一区二区 | 久久久免费电影 | 久久精精品 | 中国产一级毛片 | 国内免费视频成人精品 | 色妞欧美| 亚洲精品成人久久 | 看免费5xxaaa毛片 | 成人毛片在线免费观看 | 亚洲精品日韩欧美 | 人人看人人艹 | 久久久成人动漫 | 国产精品一区二区手机在线观看 | 国产成人自拍视频在线观看 | 羞羞羞网站| 斗破苍穹在线观看免费完整观看 | 午夜精品一区二区三区免费 | 久久免费精品 | 污污黄|