android 鍵盤遮蓋輸入框_Android軟鍵盤擋住輸入框的終極解決方案

前言

開發做得久了,總免不了會遇到各種坑。

而在Android開發的路上,『軟鍵盤擋住了輸入框』這個坑,可謂是一個曠日持久的巨坑——來來來,我們慢慢看。

入門篇

最基本的情況,如圖所示:在頁面底部有一個EditText,如果不做任何處理,那么在軟鍵盤彈出的時候,就有可能會擋住EditText。

對于這種情況的處理其實很簡單,只需要在AndroidManifest文件中對activity設置:android:windowSoftInputMode的值adjustPan或者adjustResize即可,像這樣:

android:name=".MainActivity"

android:windowSoftInputMode="adjustPan" >

...

一般來說,他們都可以解決問題,當然,adjustPan跟adjustResize的效果略有區別。

adjustPan是把整個界面向上平移,使輸入框露出,不會改變界面的布局;

adjustResize則是重新計算彈出軟鍵盤之后的界面大小,相當于是用更少的界面區域去顯示內容,輸入框一般自然也就在內了。

↑↑↑ OK,這只是入門,基本上地球上所有的Android工程師都能搞定。

別急,看下面~

加上WebView試試看?坑來了……

上面的入門篇中,軟鍵盤是由原生的EditText觸發彈出的。而在H5、Hybrid幾乎已經成為App標配的時候,我們經常還會碰到的情況是:軟鍵盤是由WebView中的網頁元素所觸發彈出的。

情況描述

這時候,情況就會變得復雜了:

首先,頁面是非全屏模式的情況下,給activity設置adjustPan會失效。

其次,頁面是全屏模式的情況,adjustPan跟adjustResize都會失效。

——解釋一下,這里的全屏模式即是頁面是全屏的,包括Application或activity使用了Fullscreen主題、使用了『狀態色著色』、『沉浸式狀態欄』、『Immersive Mode』等等——總之,基本上只要是App自己接管了狀態欄的控制,就會產生這種問題。

下面這個表格可以簡單列舉了具體的情況。

為什么說它是個坑?”issue 5497”

上面表格的這種情況并非是Google所期望的,理想的情況當然是它們都能正常生效才對——所以這其實是Android系統本身的一個BUG。

為什么文章開頭說這是個坑呢?

——因為這個BUG從Android1.x時代(2009年)就被報告了,而一直到了如今的Android7.0(2016年)還是沒有修復……/(ㄒoㄒ)/

可以說這不僅是個坑,而且還是個官方挖的坑~

“issue 5497”,詳情傳送門 ? Issue 5497 - android -WebView adjustResize windowSoftInputMode breaks when activity is fullscreen - Android Open Source Project - Issue Tracker - Google Project Hosting

當然了,不管坑是誰挖的,最終還是要開發者來解決。

遇到坑之后,有兩種方法可以過去:躲,或者填。

躲坑姿勢

如前文所示,出現坑的條件是:帶有WebView的activity使用了全屏模式或者adjustPan模式。

那么躲坑的姿勢就很簡單了——

如果activity中有WebView,就不要使用全屏模式,并且把它的windowSoftInputMode值設為adjustResize就好了嘛

怎么樣,是不是很簡單?

但總有些時候,是需要全屏模式跟WebView兼得的,這時候,躲坑就不行了,我們需要一個新的填坑的姿勢。幸好,開發者的智慧是無窮的,這個坑出現了這么多年,還是有人找到了一些解決方案的。

AndroidBug5497Workaround

我個人認為最好的解決方案是這個:AndroidBug5497Workaround,只需要一個神奇的AndroidBug5497Workaround類。

看名字就知道,它是專門用來對付”5497”問題的,使用步驟也是超級簡單:

把AndroidBug5497Workaround類復制到項目中

在需要填坑的activity的onCreate方法中添加一句AndroidBug5497Workaround.assistActivity(this)即可。

經過測試,基本在各個Android版本上都可用,效果基本與設置了adjustResize相當。

看一個對比圖:

來自我廠App的某個使用WebView的全屏模式Activity頁面,從左到右分別是:沒有軟鍵盤的樣式、軟鍵盤擋住輸入框的效果、以及使用AndroidBug5497Workaround之后的最終效果。

它的原理是什么?

這個炫酷AndroidBug5497Workaround類,其實并不是很復雜,只有幾十行代碼,先貼在這里:

public class AndroidBug5497Workaround {

// For more information, see https://code.google.com/p/android/issues/detail?id=5497

// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

public static void assistActivity (Activity activity) {

new AndroidBug5497Workaround(activity);

}

private View mChildOfContent;

private int usableHeightPrevious;

private FrameLayout.LayoutParams frameLayoutParams;

private AndroidBug5497Workaround(Activity activity) {

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);

mChildOfContent = content.getChildAt(0);

mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

public void onGlobalLayout() {

possiblyResizeChildOfContent();

}

});

frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();

}

private void possiblyResizeChildOfContent() {

int usableHeightNow = computeUsableHeight();

if (usableHeightNow != usableHeightPrevious) {

int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();

int heightDifference = usableHeightSansKeyboard - usableHeightNow;

if (heightDifference > (usableHeightSansKeyboard/4)) {

// keyboard probably just became visible

frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;

} else {

// keyboard probably just became hidden

frameLayoutParams.height = usableHeightSansKeyboard;

}

mChildOfContent.requestLayout();

usableHeightPrevious = usableHeightNow;

}

}

private int computeUsableHeight() {

Rect r = new Rect();

mChildOfContent.getWindowVisibleDisplayFrame(r);

return (r.bottom - r.top);// 全屏模式下: return r.bottom

}

}

代碼大致是做了這么幾件事:

1.找到activity的根View

看一下入口的代碼:

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);

mChildOfContent = content.getChildAt(0);

其中,第一行中的android.R.id.content所指的View,是Android所有Activity界面上開發者所能控制的區域的根View。

如果Activity是全屏模式,那么android.R.id.content就是占滿全部屏幕區域的。

如果Activity是普通的非全屏模式,那么android.R.id.content就是占滿除狀態欄之外的所有區域。

其他情況,如Activity是彈窗、或者7.0以后的分屏樣式等,android.R.id.content也是彈窗的范圍或者分屏所在的半個屏幕——這些情況較少,就暫且不考慮了。

我們經常用的setContentView(View view)/setContent(int layRes)其實就是把我們指定的View或者layRes放到android.R.id.content里面,成為它的子View。

所以,然后,第二行content.getChildAt(0)獲取到的mChildOfContent,其實也就是用以獲取到我們用setContentView放進去的View。

2.設置一個Listener監聽View樹變化

mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener({ //簡化了寫法

possiblyResizeChildOfContent();

});

View.getViewTreeObserver()可以獲取一個ViewTreeObserver對象——這個對象是一個觀察者,專門用以監聽當前View樹所發生的一些變化。這里所注冊的addOnGlobalLayoutListener,就是會在當前的View樹的全局布局(GlobalLayout)發生變化、或者其中的View可視狀態有變化時,進行通知回調。

——『軟鍵盤彈出』,則是會觸發這個事件的一個源。 (軟鍵盤彈出會使GlobalLayout發生變化)

也就是說,現在能監聽到『軟鍵盤彈出』的事件了。

3.界面變化之后,獲取”可用高度”

當軟鍵盤彈出了之后,接下來的事情是獲取改變之后的界面的可用高度(可以被開發者用以顯示內容的高度)。

直接看代碼:

private int computeUsableHeight() {

Rect rect = new Rect();

mChildOfContent.getWindowVisibleDisplayFrame(rect);

// rect.top其實是狀態欄的高度,如果是全屏主題,直接 return rect.bottom就可以了

return (rect.bottom - rect.top);

}

View.getWindowVisibleDisplayFrame(Rect rect),這行代碼能夠獲取到的Rect——就是界面除去了標題欄、除去了被軟鍵盤擋住的部分,所剩下的矩形區域——如圖所示,紅框中的區域。

Rect區域示意圖

也可以看出:

rect.top值,其實就是標題欄的高度。(實際上,這也常常被用作為獲取標題欄高度的方法)

屏幕高度-rect.bottom,是軟鍵盤的高度。(獲取軟鍵盤高度的方法也出現了)

這時,就有:

全屏模式下,可用高度 = rect.bottom

非全屏模式,可用高度 = rect.bottom - rect.top

4.最后一步,重設高度

我們計算出的可用高度,是目前在視覺效果上能看到的界面高度。但當前界面的實際高度是比可用高度要多出一個軟鍵盤的距離的。

所以,最后一步,就是把界面高度置為可用高度——大功告成。

private void possiblyResizeChildOfContent() {

int usableHeightNow = computeUsableHeight();

if (usableHeightNow != usableHeightPrevious) {

int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();

int heightDifference = usableHeightSansKeyboard - usableHeightNow;

if (heightDifference > (usableHeightSansKeyboard/4)) {

// keyboard probably just became visible

frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;

} else {

// keyboard probably just became hidden

frameLayoutParams.height = usableHeightSansKeyboard;

}

mChildOfContent.requestLayout();

usableHeightPrevious = usableHeightNow;

}

}

上面的代碼里添加了一個”heightDifference > (usableHeightSansKeyboard/4)”的判斷,這是為了去除無謂的干擾。因為能觸發OnGlobalLayout事件的原因有很多,不止是軟鍵盤的彈出變化,還包括各種子View的隱藏顯示變化等,它們對界面高度的影響有限。加上了這個判斷之后,只有界面的高度變化超過1/4的屏幕高度,才會進行重新設置高度,基本能保證代碼只響應軟鍵盤的彈出。

總結

總結起來,就是這樣:

普通Activity(不帶WebView),直接使用adjustpan或者adjustResize

如果帶WebView:

a) 如果非全屏模式,可以使用adjustResize

b) 如果是全屏模式,則使用AndroidBug5497Workaround進行處理。

以上所述是小編給大家介紹的Android軟鍵盤擋住輸入框的終極解決方案,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!

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

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

相關文章

最全面的幾何畫板實用教程視頻免費下載

不同的選擇就會有不同的人生夜,這里小編為奮斗在教學一線的老師們送個大福利,這也是老師們充實自己的好去處。作為數學老師一枚,在平時的教學中應該用到很多教學輔助軟件,而幾何畫板就是其中一款。眾所周知,幾何畫板是…

Redis(1):簡介

2019獨角獸企業重金招聘Python工程師標準>>> Redis之父Salvatore Sanfilippo于2009年將Redis開源。VMware公司從2010年開始贊助Redis的開發,Salvatore Sanfilippo和Pieter Noordhuis(另一名主要的代碼貢獻者)同年加入VMware,全職開發Redis。R…

小程序服務器域名5次_為什么您不應該在100美元的服務器上用5天的時間構建面向500,000個用戶的應用程序...

小程序服務器域名5次by Howard Lo霍華德羅 為什么您不應該在100美元的服務器上用5天的時間構建面向500,000個用戶的應用程序 (Why you shouldn’t build an app aimed at 500,000 users in 5 days on a $100 server) A few days ago, I read Erik Duindam’s “How I built an…

tp5 異步處理_tp5框架ajax異步添加數據的代碼實現

本篇文章給大家帶來的內容是關于tp5框架ajax異步添加數據的代碼實現,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。ajax異步無刷新處理數據的用戶體驗還是不錯的,在我們的項目開發中算是經常使用到的一個知識點。…

java中類型轉換的造型_Java總結篇系列:類型轉換/造型

Java中,經常可以遇到類型轉換的場景,從變量的定義到復制、數值變量的計算到方法的參數傳遞、基類與派生類間的造型等,隨處可見類型轉換的身影。Java中的類型轉換在Java編碼中具有重要的作用。首先,來了解下數據類型的基本理解&…

Google Maps API V3 之 路線服務

Google官方教程: Google 地圖 API V3 使用入門 Google 地圖 API V3 針對移動設備進行開發 Google 地圖 API V3 之事件 Google 地圖 API V3 之控件 Google 地圖 API V3 之 疊加層 Google Maps API V3 之繪圖庫 信息窗口 Google Maps API V3 之 圖層 Google Maps API …

day 04 作業 循環和分之

# 讀程序&#xff0c;總結程序的功能:"""1.求2 的20次方numbers1for i in range(0,20):numbers*2print(numbers)2.求100以內能整除3 或 7的數&#xff0c;并21不能整除的數summation 0num 1while num<100: if (num%30 or num%70) and num%21!0: …

Mysql數據庫多實例配置

二進制安裝&#xff1a; [rootlufengcentos ~]# mkdir /home/lufeng/tools -p [rootlufengcentos ~]# cd /home/lufeng/tools [rootlufengcentos tools]# rz [rootlufengcentos tools]# tar xf mysql-5.5.49-linux2.6-x86_64.tar.gz [rootlufengcentos tools]# mkdir -p /ap…

了解ES6 The Dope Way第三部分:模板文字,擴展運算符和生成器!

by Mariya Diminsky通過瑪麗亞迪明斯基(Mariya Diminsky) 了解ES6 The Dope Way第三部分&#xff1a;模板文字&#xff0c;擴展運算符和生成器&#xff01; (Learn ES6 The Dope Way Part III: Template Literals, Spread Operators, and Generators!) Welcome to Part III of…

Jenkins --SVN

項目名稱&#xff1a;XXX 源碼管理&#xff1a; None 發布之前&#xff0c;獲取源碼 編譯獲取后的代碼&#xff0c;指定vs版本 將源碼拷貝至jenkins工作控件 d:\jenkins\workspace\.. 刪除指定文件 用管理員命令 將Jenkins工作空間的代碼發布至指定路徑轉載于:https://www.cnbl…

keil5圖標變成白色_電腦桌面圖標全部變成白色的解決辦法

系統桌面圖標全部變成一個樣子的白色圖標&#xff0c;這是怎么回事&#xff1f;電腦桌面的圖標全部變成白色該如何解決&#xff1f;下面為大家解答。解決辦法&#xff1a;1.首先嘗試最簡單的方法操作看看&#xff0c;登錄到系統桌面&#xff0c;右鍵桌面空白處點擊打開“個性化…

java 繪圖球的移動_求助在JFrame上繪制移動的小球

我想在JFrame中或者Frame中添加一張背景圖片&#xff0c;然后在這圖片上畫出會移動的小球&#xff0c;怎么實現&#xff1f;我的代碼把添加背景圖片去掉&#xff0c;小球就正常運行了&#xff0c;怎么修改啊&#xff1f;希望各位大俠指教不勝感激&#xff01;&#xff01;&…

apache mesos_試用Apache Mesos HTTP API獲得樂趣和收益

apache mesosby Marco Massenzio由Marco Massenzio 試用Apache Mesos HTTP API獲得樂趣和收益 (Experimenting with the Apache Mesos HTTP API for Fun and Profit) Apache Mesos is a tool used in production at large-scale services like Twitter and Airbnb. Here’s it…

epoll哪些觸發模式_5.epoll的水平觸發和邊緣觸發

本篇是多路復用的第五篇&#xff0c;主要來講解epoll的水平觸發和邊緣觸發是怎么回事。一、概念介紹EPOLL事件有兩種模型&#xff0c;水平出發和邊緣觸發&#xff0c;如下所示&#xff1a;1. Level Triggered (LT) 水平觸發1. socket接收緩沖區不為空 有數據可讀 讀事件一直觸發…

HC系列藍牙模塊連接單片機與電腦,傳輸數據(藍牙心電測試)

畢設做無線心電監護。有線的做出來了&#xff0c;AD8232MCULabVIEW上位機。pcb還沒時間搞&#xff0c;這個9*7*2.5cm拿來測試能用。 自己做了AD8232的模擬前端&#xff0c;打的板子還沒到沒法測試。 雖然比較水&#xff0c;但看起來任務也完成的差不多了&#xff0c;于是就想加…

java實現社交平臺_GitHub - akpaul9527/symphony: 一款用 Java 實現的現代化社區(論壇/BBS/社交網絡/博客)平臺。...

下一代的社區系統&#xff0c;為未來而構建簡介Symphony([?s?mf?ni]&#xff0c;n.交響樂)是一個現代化的社區平臺&#xff0c;因為它&#xff1a;實現了面向內容討論的論壇實現了面向知識問答的社區包含了面向用戶分享、交友、游戲的社交網絡100% 開源動機很多社區論壇系統…

遠程連接本地mongodb 數據庫

綁定本地IP即可 start mongod --dbpath D:\mongodb\data\db --bind_ip 192.168.31.143 轉載于:https://www.cnblogs.com/yang-xiansen/p/9884598.html

qt日志實現

qt的日志有四個級別&#xff1a;qDebug&#xff1a; 調試信息qWarning&#xff1a; 警告信息qCritical&#xff1a; 嚴重錯誤qFatal&#xff1a; 致命錯誤可以通過<QtGlobal>下的void qCritical ( const char * msg, ... );void qDebug ( const char *…

mvc 視圖和模型的對應_通過在酒吧訂購飲料來解釋模型視圖控制器(MVC)

mvc 視圖和模型的對應by Kevin Kononenko凱文科諾年科(Kevin Kononenko) 通過在酒吧訂購飲料來解釋模型視圖控制器(MVC) (Model-View-Controller (MVC) Explained Through Ordering Drinks At The Bar) 如果您去過酒吧&#xff0c;那么MVC并不難。 (If you have been to a bar…

nodejs計算時間間隔_Javascript計算時間差的函數分享

核心代碼/** 獲得時間差,時間格式為 年-月-日 小時:分鐘:秒 或者 年/月/日 小時&#xff1a;分鐘&#xff1a;秒* 其中&#xff0c;年月日為全格式&#xff0c;例如 &#xff1a; 2010-10-12 01:00:00* 返回精度為&#xff1a;秒&#xff0c;分&#xff0c;小時&#xff0c;天*…