android 如何判定底部導航欄顯示時 不是鍵盤顯示

在 Android 中判定底部導航欄是否顯示時,核心痛點是?區分 “導航欄的底部 Insets” 和 “軟鍵盤彈出的底部 Insets”—— 兩者都會導致?getSystemWindowInsetBottom()?返回非零值,直接判斷會誤將鍵盤彈出當成導航欄顯示。以下是基于?WindowInsets 類型區分?的精準解決方案,兼容不同 Android 版本和場景。

核心原理:通過 Insets 類型過濾鍵盤

Android 的?WindowInsets?會標記不同來源的 “插入區域”(如導航欄、狀態欄、軟鍵盤),通過?WindowInsetsCompat.Type?可精準過濾出?僅由導航欄貢獻的底部 Insets,從而排除鍵盤干擾。

關鍵類型說明:

Insets 類型含義需排除 / 保留
Type.NAVIGATION_BARS系統導航欄(底部 / 側邊)保留(目標判斷對象)
Type.IME軟鍵盤(Input Method Editor)排除(干擾項)
Type.STATUS_BARS狀態欄(頂部)排除(與底部無關)

方案實現:兼容高低版本的工具類

以下工具類支持?Android 14(API 34)及以下版本,通過?WindowInsetsCompat?統一處理 Insets 類型,精準判斷導航欄可見性并獲取高度。

import android.view.View;
import androidx.core.view.WindowInsetsCompat;/*** 精準判斷底部導航欄是否顯示(排除軟鍵盤干擾)*/
public class NavigationBarChecker {/*** 判定底部導航欄當前是否可見(排除鍵盤)* @param rootView 頁面根布局(如 Activity 的 contentView、Fragment 的根View)* @return true:導航欄顯示;false:導航欄隱藏或當前是鍵盤彈出*/public static boolean isNavigationBarVisible(View rootView) {if (rootView == null) {return false;}// 1. 獲取根View的WindowInsets(包含所有插入區域信息)WindowInsetsCompat insetsCompat = ViewCompat.getRootWindowInsets(rootView);if (insetsCompat == null) {return false; // 極端情況(如View未附著到窗口),返回隱藏}// 2. 關鍵:僅獲取“導航欄”貢獻的底部Insets(排除鍵盤、狀態欄等)// Type.NAVIGATION_BARS:指定只計算導航欄的Insetsint navBarBottomInset = insetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;// 3. 底部Insets > 0 說明導航欄在底部顯示(若為側邊導航欄,bottom會是0,需額外判斷left/right)return navBarBottomInset > 0;}/*** 獲取底部導航欄的真實高度(排除鍵盤干擾)* @param rootView 頁面根布局* @return 導航欄高度(px);0:導航欄隱藏*/public static int getNavigationBarHeight(View rootView) {if (rootView == null) {return 0;}WindowInsetsCompat insetsCompat = ViewCompat.getRootWindowInsets(rootView);if (insetsCompat == null) {return 0;}// 同樣只取導航欄的底部Insets,即為導航欄高度return insetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;}/*** (擴展)判斷是否為軟鍵盤彈出狀態(輔助驗證)* @param rootView 頁面根布局* @return true:鍵盤顯示;false:鍵盤隱藏*/public static boolean isKeyboardVisible(View rootView) {if (rootView == null) {return false;}WindowInsetsCompat insetsCompat = ViewCompat.getRootWindowInsets(rootView);if (insetsCompat == null) {return false;}// 僅判斷“鍵盤”貢獻的底部Insets:>0 說明鍵盤彈出//對core 版本有要求,太低找不到//dependencies {//implementation 'androidx.core:core:1.5.0'//}int keyboardBottomInset = insetsCompat.getInsets(WindowInsetsCompat.Type.ime()).bottom;return keyboardBottomInset > 0;}
}

關鍵細節說明

1. 為什么必須用?ViewCompat.getRootWindowInsets()
  • 避免直接調用?rootView.getRootWindowInsets():該方法在 API 23(Android 6.0)以上才可用,ViewCompat?會自動兼容低版本(API 14+),無需額外版本判斷。
  • 確保獲取的是 “根 View 的 Insets”:只有根布局(如?setContentView?傳入的 View)能拿到完整的系統 Insets,子 View 可能因布局嵌套導致 Insets 被截斷。
2. 如何處理 “側邊導航欄”(如平板橫屏)?

部分設備(平板、折疊屏)在橫屏時會將導航欄放在左側 / 右側,此時?bottom?Insets 為 0,需額外判斷?left?或?right

// 擴展:判斷任意位置的導航欄是否可見(含側邊)
public static boolean isAnyNavigationBarVisible(View rootView) {if (rootView == null) return false;WindowInsetsCompat insetsCompat = ViewCompat.getRootWindowInsets(rootView);if (insetsCompat == null) return false;WindowInsetsCompat.Insets navInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars());// 左/右/下 任意一個方向有Insets,說明導航欄可見return navInsets.left > 0 || navInsets.right > 0 || navInsets.bottom > 0;
}
3. 兼容 Android 14(API 34)的新變化

Android 14 新增了?WindowInsets.Type.systemBars()(包含狀態欄 + 導航欄),但?Type.navigationBars()?仍完全兼容,無需修改代碼 ——WindowInsetsCompat?已內部適配新 API,保證低版本行為一致。

使用示例(在 Activity 中)

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 獲取頁面根布局(必須是setContentView的根View)View rootView = findViewById(android.R.id.content); // 通用獲取根View的方式// 1. 監聽導航欄可見性變化(如鍵盤彈出/收起、旋轉屏幕時)ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> {// 判斷導航欄是否顯示(排除鍵盤)boolean isNavVisible = NavigationBarChecker.isNavigationBarVisible(rootView);// 獲取導航欄高度int navHeight = NavigationBarChecker.getNavigationBarHeight(rootView);// 判斷鍵盤是否顯示(輔助)boolean isKeyboard = NavigationBarChecker.isKeyboardVisible(rootView);// 業務邏輯:如更新UI、調整布局Log.d("NavChecker", "導航欄可見:" + isNavVisible + ",高度:" + navHeight + "px,鍵盤可見:" + isKeyboard);return insets; // 必須返回Insets,否則后續監聽會失效});// 2. 主動觸發一次判斷(如頁面初始化時)boolean initNavVisible = NavigationBarChecker.isNavigationBarVisible(rootView);int initNavHeight = NavigationBarChecker.getNavigationBarHeight(rootView);}
}

常見問題排查

  1. 返回值始終為 0?

    • 檢查?rootView?是否為頁面根布局(如用?findViewById(android.R.id.content)?替代子 View)。
    • 確保布局未設置?fitsSystemWindows="true":該屬性會讓 View 消費 Insets,導致?getInsets()?返回 0(如需使用,需在根 View 的父布局設置)。
  2. 鍵盤彈出時誤判為導航欄?

    • 確認代碼中使用?WindowInsetsCompat.Type.navigationBars()?而非?Type.systemBars()?或直接?getSystemWindowInsetBottom()—— 后者會包含鍵盤 Insets。
  3. 低版本(API < 21)不生效?

    • Android 5.0(API 21)以下無官方 Insets API,若需兼容,可通過?反射獲取系統資源?間接判斷(但精度較低,建議最低兼容到 API 21):
      // 兼容API < 21:通過系統資源判斷導航欄是否存在(無法實時判斷顯示/隱藏)
      public static boolean hasNavigationBar(Context context) {Resources res = context.getResources();int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android");if (resourceId > 0) {return res.getBoolean(resourceId);}return false; // 無法判斷時默認返回false
      }
      

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96657.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96657.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96657.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

你知道服務器和電腦主機的區別嗎?

我們都知道服務器和臺式主機有著不同之處&#xff0c;但具體說出個一二三來很多人還是一頭霧水&#xff0c;也就是知其然不知其所以然&#xff0c;都是CPU主板 內存 硬盤 電源&#xff0c;撐死就差一個顯卡不同&#xff0c;但其實服務器和我們正常使用的臺式主機差距很大&#…

什么是包裝類

什么是包裝類 在Java中&#xff0c;包裝類&#xff08;Wrapper Class&#xff09;是為基本數據類型提供的對應的引用類型。Java中的基本數據類型&#xff08;如int、char、boolean等&#xff09;不是對象&#xff0c;為了在需要對象的場景中使用基本數據類型&#xff08;如集合…

用Python打造專業級老照片修復工具:讓時光倒流的數字魔法

在這個數字化時代&#xff0c;我們手中珍藏著許多泛黃、模糊、甚至有劃痕的老照片。這些照片承載著珍貴的回憶&#xff0c;但時間的侵蝕讓它們失去了往日的光彩。今天&#xff0c;我將帶您一起用Python開發一個專業級的老照片修復工具&#xff0c;讓這些珍貴的記憶重現光彩。為…

linux中查找包含xxx內容的文件

linux中怎么查找哪個文件包含xxx內容 在Linux中查找包含特定內容的文件 在Linux系統中&#xff0c;有幾種常用方法來查找包含特定內容的文件。以下是幾種最有效的方法&#xff1a;1. 使用 grep 命令&#xff08;最常用&#xff09; 基本語法&#xff1a;bash grep -r "搜索…

sklearn 加州房價數據集 fetch_california_housing 出錯 403: Forbidden 修復方案

問題 加載加州房價數據時出現 403 錯誤 HTTP Error 403: Forbidden from sklearn.datasets import fetch_california_housingcalifornia fetch_california_housing() print(california.target.shape) 解決方案 運行下述代碼&#xff0c;然后再運行上述的 fetch_california_hou…

嵌入式學習---(硬件)

1、在LED實驗中&#xff0c;在對Soc引腳配置時都做了哪些工作&#xff1f;復用功能配置操作寄存器&#xff1a;IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03將引腳的低 4 位設置為 0101&#xff0c;將引腳復用為 GPIO 功能電氣特性配置操作寄存器&#xff1a;IOMUXC_SW_PAD_CTL_PAD_GPIO1…

微信小程序開發教程(十一)

目錄&#xff1a;1.上拉觸底案例-初步實現上拉觸底效果2.上拉觸底案例-添加loading效果3.上拉觸底案例-節流處理4.擴展-自定義編譯模式1.上拉觸底案例-初步實現上拉觸底效果頁面加載的時候調用這個方法&#xff1a;設置樣式&#xff1a;下拉觸底后繼續調用獲取顏色的方法2.上拉…

Android相機API2,基于GLSurfaceView+SurfaceTexture實現相機預覽,集成的相機算法采用GPU方案,簡要說明

Android相機API2&#xff0c;基于GLSurfaceViewSurfaceTexture實現相機預覽&#xff0c;集成的相機算法采用GPU方案&#xff0c;簡要流程如下(不疊加相機算法的預覽顯示流程也大體如此&#xff0c;只是去掉了算法部分)&#xff1a;進入相機&#xff1a;1&#xff0c;新建實現了…

[code-review] 日志機制 | `LOG_LEVEL`

第6章&#xff1a;日志機制&#xff08;調試&#xff09; 歡迎來到我們了解ChatGPT-CodeReview項目的最后一章 在第5章&#xff1a;文件過濾邏輯&#xff08;范圍管理器&#xff09;中&#xff0c;我們學習了機器人如何智能地決定哪些文件需要發送給AI審查。 但一旦機器人開…

n8n工作流平臺入門學習指南

目錄 1、基礎背景 2、核心概念 2.1 節點(Nodes) 2.2 連接(Connections) 2.3 工作流(Workflows) 3、常用節點說明 4、基于Docker快速部署 5、學習資料 6、常見問題 強烈推薦&#xff0c;大家不懂的直接問&#xff1a;N8N大師&#xff08;GPT&#xff09;&#xff0c;科…

【Oracle經驗分享】字符串拼接過長問題的解決方案 —— 巧用 XMLAGG

&#x1f4d1; 目錄&#x1f50d; 問題背景?? 常見拼接方式的限制&#x1f4a1; XMLAGG 的解決方案&#x1f4dd; 示例代碼&#x1f4cc; 注意事項? 總結&#x1f50d; 問題背景在日常開發中&#xff0c;我們經常需要把多行數據拼接成一個字符串。例如將某個字段的多條記錄拼…

AJAX入門-URL、參數查詢、案例查詢

本系列可作為前端學習系列的筆記&#xff0c;代碼的運行環境是在VS code中&#xff0c;小編會將代碼復制下來&#xff0c;大家復制下來就可以練習了&#xff0c;方便大家學習。 HTML、CSS、JavaScript系列文章 已經收錄在前端專欄&#xff0c;有需要的寶寶們可以點擊前端專欄查…

【SpringBoot】24 核心功能 - Web開發原理 -Spring Boot 異常處理機制

前言 在開發 Web 應用程序時&#xff0c;異常處理是一個至關重要的部分。Spring Boot 提供了一套強大的異常處理機制&#xff0c;使得開發者能夠輕松地處理和響應各種異常情況。本文將深入探討 Spring Boot 中的異常處理機制&#xff0c;包括默認的錯誤處理規則、定制錯誤處理邏…

JVM第一部分

PC寄存器&#xff1a;存儲的是數字 0, 3, 6, 10, 17 這樣的字節碼偏移量。 LineNumberTable&#xff1a;是一個映射表&#xff0c;它將上述的偏移量“翻譯”成我們程序員能看懂的源代碼行號。 JVM堆 JVM堆由兩部分組成&#xff1a;年輕代老年代 年輕代包括三部分&#xff1a;ed…

IDEA使用Maven和MyBatis簡化數據庫連接(配置篇)

目錄&#xff1a; Maven:簡化項目構建 MyBatis:簡化Jdbc Maven&#xff1a;是一款項目構建與依賴管理工具&#xff0c;核心作用是自動化項目編譯、打包等流程&#xff0c;并統一管理項目所需的第三方 Jar 包&#xff08;如 MyBatis 的 Jar 包&#xff09;。 MyBatis&#xf…

Java 泛型詳解:從基礎到高級應用

目錄 一、泛型的基本概念 為什么需要泛型&#xff1f; 二、泛型類與泛型接口 【1】定義泛型類 【2】定義泛型接口 三、泛型方法 四、泛型通配符 【1】無界通配符&#xff08;?&#xff09; 【2】上界通配符&#xff08;? extends T&#xff09; 【3】下界通配符&am…

嵌入式 Linux 啟動機制全解析:從 Boot 到 Rootfs

&#x1f680; 嵌入式 Linux 啟動機制全解析&#xff1a;從 Boot 到 Rootfs 在嵌入式系統中&#xff0c;Linux 的啟動流程不僅是內核加載的過程&#xff0c;更是 bootloader、設備樹、初始根文件系統、啟動配置文件等多個組件協同工作的結果。不同的文件系統和啟動方式會影響系…

Python 操作Office的PPT、Word、Excel,同時兼容WPS

文章目錄概要一、環境準備1. 安裝必要的Python庫2. 系統要求二、核心實現原理1. 檢測已安裝的Office類型2. 初始化對應的應用程序三、完整代碼實現四、使用示例五、WPS兼容處理詳解1. 形狀和文本框訪問兼容處理2. PPT圖片粘貼兼容處理3. 資源釋放的重要性六、圖片操作實現詳解1…

ISP之DHCPv6-PD(前綴代理)為用戶下發前綴

一、組網需求家庭用戶要使用IPv6地址接入互聯網。為方便用戶接入&#xff0c;運營商使用DHCPv6-PD的方式給家用路由器下發IPv6地址前綴&#xff0c;用戶路由器LAN側不需要手工指定鏈路的IPv6地址前綴&#xff0c;家用路由器可以給用戶終端自動配置IPv6地址和其它網絡參數。本例…

Django全棧班v1.04 Python基礎語法 20250912 上午

rm 刪除命令 注意&#xff1a;刪除操作是不可逆的&#xff0c;一旦刪除就無法撤銷&#xff0c;請謹慎使用。刪除文件&#xff1a; rm file.py遞歸刪除目錄&#xff1a; rm -r demo/強制刪除&#xff1a; rm -f file.py交互式刪除&#xff1a; rm -i *.txt課程定位 “學習Python…