網站首頁 編程語言 正文
前言
在Android屏幕的空間中,大部分的區域我們都是可以隨意繪制,只有一部分區域是顯示的固定內容:
- 狀態欄
- 標題欄(ActionBar)
- 頁面內容(Content)
- 導航欄
其中標題欄是可選的,除了Material風格的應用應用的并不多,頁面內容就是android.R.id.content
是Activity的主要內容。
而我們主要需要討論的就是?狀態欄和導航欄,因為這兩個區域在不同設備類型,不同的Android版本和不同的廠商下大小和效果是不同的,等等。這些差異無疑增加了我們做頁面適配的復雜程度,也更容易出現兼容問題。
在2017年下半年iPhone X的發布,引入了劉海屏設備,導致了藍綠大廠爭相效仿,同時又自成一派,頗有一番百家爭鳴之象。 這也導致了一個新的問題?劉海區域適配?,那時候Android才8.1,并沒有API來支持這屏幕上這多出來的一塊區域,不過好在大部分設備在定制時劉海和狀態欄高度是一致的。
終于在2018年發布的Android 9中Google正式支持了劉海屏,定制了規范約束了設備廠商,減輕了劉海屏適配的差異問題,但是根源問題并沒有解決。因為劉海區域的存在,可能會出現頁面內容被遮擋,比如:啟用頁廣告跳過按鈕被遮擋的問題,導致被應用商店拒掉的風險。
不過好在Android 9中要求劉海設備必須有以下行為:
- 一條邊緣最多只能包含一個劉海。
- 一臺設備不能有兩個以上的劉海。
- 設備的兩條較長邊緣上不能有劉海。
- 在未設置特殊標志的豎屏模式下,狀態欄的高度必須與劉海的高度持平。
- 默認情況下,在全屏模式或橫屏模式下,整個劉海區域必須顯示黑邊。
劉海高度默認是和狀態欄高度一致依舊沒有變,所以問題又回到了狀態欄區域的處理。
描述
所以肯定有同學說了:直接獲取狀態欄高度不就可以了適配劉海屏了。像這樣:
val top = context.getStatusBarHeight() titleBar.setPadding(0, top, 0, 0)
這么說也沒有錯,大部分情況下是沒有問題的。但是既然官方已經適配劉海屏了,也為我們提供了新的API為什么不用呢:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { window.decorView.post { val top = window.decorView.rootWindowInsets?.displayCutout?.safeInsetTop ?: 0 // val bottom = window.decorView.rootWindowInsets?.displayCutout?.safeInsetBottom ?: 0 titleBar.setPadding(0, top, 0, 0) } }
上面的方案實際上可以獲取上下左右四個方向的安全距離,但大部分情況我們只需要處理頂部就可以了。實際上這已經可以解決我們的問題了,但是還有更好的解決方案方案:
添加依賴:
implementation 'androidx.core:core:1.7.0' // 老版本也可以,但是getInsets() API 還沒添加 // implementation 'androidx.core:core:1.3.0'
使用ViewCompat工具:
ViewCompat.setOnApplyWindowInsetsListener(titleBar) { view: View, insets: WindowInsetsCompat -> //val top = insets.systemWindowInsetTop // 高版本已經過時,可以用下面的api替換 val stableInsets = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) titleBar.setPadding(0, stableInsets.top, 0, 0) return@setOnApplyWindowInsetsListener insets }
實際上屏幕安全距離,基本上全部圍繞這一個API,Google也推薦我們這么做,在很多系統控件都能看到它的影子,比如:AppBarLayout、DrawerLayout、NavigationBarView
等等都有用到,內部都是來處理系統安全距離的。
系統欄適配
上面提到了手機有各種系統欄(狀態欄、導航欄),如果一個全屏+劉海屏+透明系統欄+屏幕旋轉的頁面處理這些安全距離就更復雜,比如短視頻頁,這里先給大家列幾條可能出現的問題:
- 沒有導航欄或者可以動態隱藏導航欄的設備
- 導航欄不會旋轉的設備(就是導航欄一直在屏幕的一個邊,不會跟隨屏幕旋轉)
- 導航欄跟隨屏幕旋轉的設備(主要是手勢導航的設備和一些平板上)
- 劉海在屏幕底部的設備(開發者選項可以開啟雙劉海模式,設備兩個短邊都有劉海)
- 底部劉海+導航欄一起顯示的設備
- ... ...
這些所有的問題通過?ViewCompat.setOnApplyWindowInsetsListener()
?來優雅處理, 通過?WindowInsetsCompat.getInsets(type)
?可以獲取系統的各個欄的大小, 我們也可以同時獲取多個系統欄的高度,各個距離內部會進行累加,返回一個類似Rect的對象,對應屏幕的左上右下需要插入的距離:
val stableInsets = insets.getInsets( WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout())
然后在對不同位置的控件添加對應的邊距。除了上面提到的三種類型的安全距離,還有一些其他的類型,有興趣的可以自己了解。
其他適配
ViewCompat.setOnApplyWindowInsetsListener()
能解決大部分安全距離的問題,但是有一點它是處理不了的,就是?屏幕圓角,這些安全距離的計算是不處理屏幕圓角的,所以如果有圓角要處理那我們就要另辟蹊徑了。
好在Android 12中官方添加了對圓角的支持:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val roundedCorner = insets.toWindowInsets() ?.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT) roundedCorner?.center }
我用了Pixel4真機發現能獲取到數據,但是模擬器獲取不到。
除了圓角支持,還有對隱私指示器提供了支持:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val rect = insets.toWindowInsets()?.privacyIndicatorBounds // 頁面控件需要避開這個區域,不然可能會被遮擋 }
隱私指示器的范圍,主要是?攝像頭和麥克風?使用中狀態的指示器邊界,如果是錄制直播或者相機的頁面需要處理這個區域。
除了圓角以外,好像沒有找到官方對打孔屏的支持,可能后面會加入對打孔屏的支持吧。
原文鏈接:https://juejin.cn/post/7106404688924246023
相關推薦
- 2022-10-28 keepalived對nginx進行高可用搭建及原理詳解_nginx
- 2022-09-03 Python?groupby函數圖文詳解_python
- 2022-06-12 淺談Android?Dialog窗口機制_Android
- 2022-11-23 Android集成GreenDao數據庫的操作步驟_Android
- 2022-02-18 ImportError:can't import name 'Flask'
- 2023-06-04 Pandas中MultiIndex選擇并提取任何行和列_python
- 2022-07-19 Linux ifconfig命令配置和顯示Linux系統網卡的網絡參數
- 2023-11-22 fatal: unable to access ‘https://github.com/xxxxx/
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支