Android 軟鍵盤相關問題

1. windowSoftInputMode屬性的使用

Android使用windowSoftInputMode來控制Activity 的主窗口與包含屏幕軟鍵盤的窗口的交互方式。 該屬性的設置影響兩個方面:

  • 當 Activity 成為用戶注意的焦點時軟鍵盤的狀態 — 隱藏還是可見。
  • 對 Activity 主窗口所做的調整 — 是否將其尺寸調小以為軟鍵盤騰出空間,或者當窗口部分被軟鍵盤遮擋時是否平移其內容以使當前焦點可見。

該設置必須是下表所列的值之一,或者是一個“state...”值加上一個“adjust...”值的組合。 在任一組中設置多個值(例如,多個“state...”值)都會產生未定義結果。各值之間使用垂直條 (|) 分隔。 例如:

<activity android:windowSoftInputMode="stateVisible|adjustResize" . . .復制代碼

此處設置的值(“stateUnspecified”和“adjustUnspecified”除外)替換主題中設置的值。

說明
"stateUnspecified"不指定軟鍵盤的狀態(隱藏還是可見)。 將由系統選擇合適的狀態,或依賴主題中的設置。這是對軟鍵盤行為的默認設置。
“stateUnchanged”當 Activity 轉至前臺時保留軟鍵盤最后所處的任何狀態,無論是可見還是隱藏。
“stateHidden”當用戶選擇 Activity 時 — 也就是說,當用戶確實是向前導航到 Activity,而不是因離開另一 Activity 而返回時 — 隱藏軟鍵盤。
“stateAlwaysHidden”當 Activity 的主窗口有輸入焦點時始終隱藏軟鍵盤。
“stateVisible”在正常的適宜情況下(當用戶向前導航到 Activity 的主窗口時)顯示軟鍵盤。
“stateAlwaysVisible”當用戶選擇 Activity 時 — 也就是說,當用戶確實是向前導航到 Activity,而不是因離開另一 Activity 而返回時 — 顯示軟鍵盤。
“adjustUnspecified”不指定 Activity 的主窗口是否調整尺寸以為軟鍵盤騰出空間,或者窗口內容是否進行平移以在屏幕上顯露當前焦點。 系統會根據窗口的內容是否存在任何可滾動其內容的布局視圖來自動選擇其中一種模式。 如果存在這樣的視圖,窗口將進行尺寸調整,前提是可通過滾動在較小區域內看到窗口的所有內容。這是對主窗口行為的默認設置。
“adjustResize”始終調整 Activity 主窗口的尺寸來為屏幕上的軟鍵盤騰出空間。
“adjustPan”不調整 Activity 主窗口的尺寸來為軟鍵盤騰出空間, 而是自動平移窗口的內容,使當前焦點永遠不被鍵盤遮蓋,讓用戶始終都能看到其輸入的內容。 這通常不如尺寸調正可取,因為用戶可能需要關閉軟鍵盤以到達被遮蓋的窗口部分或與這些部分進行交互。

系統默認值為:stateUnspecified|adjustUnspecified

上述是引用android官方文檔的說明,但是這個并不能讓我們理解所有內容。因此本次將具體探究這9個屬性是如何影響。

1. stateUnspecified

android官方描述為:不指定軟鍵盤的狀態(隱藏還是可見)。 將由系統選擇合適的狀態,或依賴主題中的設置。這是對軟鍵盤行為的默認設置。哪系統認為的合適的狀態是什么樣的呢?

我們采用如下布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>復制代碼

我們發現軟鍵盤沒有自動彈出,需要手動點擊EditText后,鍵盤才會彈出來。
如果采用如下布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" /></ScrollView>
</LinearLayout>復制代碼

我們發現軟鍵盤會自動彈出。這個就很奇怪了,為什么就加了一個ScrollView,難道是因為添加了ScrollView,軟鍵盤就可以自動彈出來嗎?我們看一下如下的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content" /></ScrollView>
</LinearLayout>復制代碼

運行代碼可以發現,這樣軟鍵盤也會不會自動彈出來。說明軟鍵盤自動彈出和ScrollView沒有直接關系。

如果我們采用如下布局,我們發現軟鍵盤還是會自動彈出

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content" /><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="測試"android:id="@+id/btn_test"/></LinearLayout></ScrollView>
</LinearLayout>復制代碼

如何依舊采用上述的布局,但是我們在onCreate中加上如下代碼

    Button button= (Button) findViewById(R.id.btn_test);button.setFocusable(true);button.setFocusableInTouchMode(true);button.requestFocus();button.requestFocusFromTouch();復制代碼

我們發現軟鍵盤將不會自動彈出來。

現在我們總結一下,當屬性設置為stateUnspecified時,系統默認時不會自動彈出軟鍵盤,但是當界面上有滾動需求時(有ListView或ScrollView等)同時有獲得焦點的輸入框軟鍵盤將自動彈出來(如果獲得焦點不是輸入框也不會自動彈出軟鍵盤)。

2. stateUnspecified

這個比較簡單,進入當前界面是否彈出軟鍵盤由上一個界面決定。如果離開上一個界面,鍵盤是打開,那邊該界面鍵盤就是打開;否則就是關閉的.

3. stateHidden

這個也比較簡單,進入當前界面不管當前上一個界面或者當前界面如何,默認不顯示軟鍵盤。

4. stateAlwaysHidden

這個參數和stateHidden的區別是當我們跳轉到下個界面,如果下個頁面的軟鍵盤是顯示的,而我們再次回來的時候,軟鍵盤就會隱藏起來。而設置為stateHidden,我們再次回來的時候,軟鍵盤講顯示出來。

5. stateVisible

設置這個屬性,進入這個界面時無論界面是否需要彈出軟鍵盤,軟鍵盤都會顯示。

6. stateAlwaysVisible

這個參數和stateAlwaysVisible的區別是當我們從這個界面跳轉到下個界面,從下個界面返回到這個界面是軟鍵盤是消失的,當回到這個界面軟鍵盤依舊可以彈出顯示,而stateVisible確不會。

上述6個屬性定義的是進入界面,軟鍵盤是否顯示的。下面3個屬性設置的是軟鍵盤和界面顯示內容之間的顯示關系。

7. adjustResize,adjustPan

我們將這兩個屬性放在一起討論。為了說明這個問題,我們先看如下的布局例子

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="3"android:background="@android:color/holo_red_dark"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="這個是一個測試"android:textSize="30sp" /></FrameLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="4"android:background="@android:color/holo_blue_light"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="這個是一個測試"android:textSize="30sp" /></FrameLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"android:background="@android:color/white"><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center" /></FrameLayout>
</LinearLayout>復制代碼

adjustResize

adjustResize

adjustPan

adjustPan

由上面兩張圖我們可以知道,如果設置adjustResize屬性,當鍵盤顯示時,通過對界面主窗口的大小調整(壓縮等)來實現留出軟鍵盤的大小空間;如果設置adjustPan屬性,當鍵盤顯示時,通過對界面布局的移動來保證輸入框可以顯示出來。

8. adjustUnspecified

這個屬性是根據界面中否有可以滾動的控件來判斷界面是采用adjustResize還是adjustPan來顯示軟鍵盤。如果有可以滾動的控制,那可以將其理解為adjustResize,通過壓縮界面來實現.但是是有一個前提的:可通過滾動在較小區域內看到窗口的所有內容。如果沒有可以滾動的控件或者不符合前提條件,則是采用adjustPan,及移動布局來實現。

2. 軟鍵盤的打開和關閉

軟鍵盤的打開和關閉主要通過InputMethodManager實現。InputMethodManager關于打開關閉軟鍵盤的方法主要有如下幾個方法。

方法說明
hideSoftInputFromInputMethod(IBinder token, int flags)關閉/隱藏軟鍵盤,讓用戶看不到軟鍵盤,但是傳入的token必須是是系統中token。
hideSoftInputFromWindow(IBinder windowToken, int flags)和下面hideSoftInputFromWindow方法一樣,只是resultReceiver傳入的值null
hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver)關閉/隱藏軟鍵盤,和第一個方法的區別是他傳入的token是系統界面中View窗口的token
showSoftInput(View view, int flags, ResultReceiver resultReceiver)和hideSoftInputFromWindow對應
showSoftInput(View view, int flags)同上面一個方法,但是默認的resultReceiver為null
showSoftInputFromInputMethod(IBinder token, int flags)和hideSoftInputFromInputMethod對應
toggleSoftInput(int showFlags, int hideFlags)該方法是切換軟鍵盤,如果軟鍵盤打開,調用該方法軟鍵盤關閉;反之如果軟鍵盤關閉,那么就打開
toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags)和上面一個方法一樣,區別是傳入的當前View的token
  1. 在上述方法中我們看到需要傳入相關flags,相關flags有如下幾個

    參數 | 說明
    -------------------|---
    HIDE_IMPLICIT_ONLY | 表示軟鍵盤只有在用戶未明確顯示的情況才被隱藏
    HIDE_NOT_ALWAYS | 表示軟鍵盤將一致隱藏,除非調用SHOW_FORCED才會顯示
    SHOW_FORCED | 表示軟鍵盤強制顯示不會被關閉,除非用戶明確的要關閉
    SHOW_IMPLICIT | 表示軟鍵盤接收到一個不明確的顯示請求。

  2. 我們經常看到用戶傳入的參數為0,不屬于上述4個,那顯示的是什么呢?其實如果傳入的hideflag的話表示的是就是關閉軟鍵盤,之前傳入的參數不會改變,showflag的話表示的是SHOW_IMPLICIT

總結:

關閉軟鍵盤的方法為

    public void hideKeyboard(View view) {((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);}復制代碼

打開關鍵盤的方法為

    public void OpenKeyboard(View view) {((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_NOT_ALWAYS);}復制代碼

3. 監聽軟鍵盤的打開和關閉

3.1 常規方法

監聽軟鍵盤的打開和關閉最常規的方法是監聽View的層次結構,這個View的層次結構的發生全局性的事件如布局發生變化等我們可以通過調用getViewTreeObserver監聽到布局的變化。代碼實例如下:

    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {// 虛擬鍵的高度int navigationBarHeight = 0;int resourceId = activityRootView.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android");//判斷是否有虛擬鍵if (resourceId > 0 && checkDeviceHasNavigationBar(activityRootView.getContext())) {navigationBarHeight = activityRootView.getResources().getDimensionPixelSize(resourceId);}// status bar的高度int statusBarHeight = 0;resourceId = activityRootView.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");if (resourceId > 0) {statusBarHeight = activityRootView.getResources().getDimensionPixelSize(resourceId);}// 獲得app的顯示大小信息Rect rect = new Rect();((Activity)activityRootView.getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);//獲得軟鍵盤的大小:屏幕高度-(status bar的高度+虛擬鍵的高度+app的顯示高度)int keyboardHeight = ((Activity) activityRootView.getContext()).getWindow().getDecorView().getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height());if (keyboardHeight>100 && !isSoftKeyboardOpened) {isSoftKeyboardOpened = true;notifyOnSoftKeyboardOpened(keyboardHeight);Log.d(TAG, "keyboard has been opened");} else  if(keyboardHeight <100 && isSoftKeyboardOpened){isSoftKeyboardOpened = false;notifyOnSoftKeyboardClosed();Log.d(TAG, "keyboard has been closed");}}} )復制代碼

status bar是否存在其實也需要判斷,但是因為app本身可以判斷當前界面是否顯示status的高度,所以上述代碼默認status顯示。

3.2 重寫根布局的onMeasure

該方法使用于windowSoftInputMode被設置為adjustResize。如上文所致,adjustResize是采用壓縮界面布局來實現軟鍵盤可以正常顯示。具體代碼如下

public class KeyBoardFrameLayout extends FrameLayout {public KeyBoardFrameLayout(@NonNull Context context) {super(context);}public KeyBoardFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public KeyBoardFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);final int actualHeight = getHeight();int keyboardHeight = actualHeight - proposedheight;if (keyboardHeight > 100) {notifyOnSoftKeyboardOpened(keyboardHeight);} else if (keyboardHeight < -100) {notifyOnSoftKeyboardClosed();}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}復制代碼

對比上述兩種方法:

  1. 第一種方法的優點是不管windowSoftInputMode被設置為什么,都可以實現軟鍵盤的開關鍵盤;第二種需要將上述的布局作為界面的根布局才能實現監聽
  2. 第一種方法的缺點是事后監聽,已當onLayout之后才會拿到監聽,這個導致界面容易出現閃屏的情況;而第二種方法是在界面onLayout之前就拿到了監聽,因此不會出現閃屏的情況。

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

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

相關文章

git php框架,如何用Git安裝TP框架

本篇文章主要給大家介紹如何用Git安裝Thinkphp框架。關于TP框架的安裝&#xff0c;想必大家都知道較為常見的方式是通過composer安裝tp框架。首先簡單的給大家介紹下Git和TP框架。Git是一個開源的分布式版本控制系統&#xff0c;可以快速&#xff0c;高效地處理從小型到大型項目…

C#EF中,使用類似于SQL中的% 模糊查詢

最近在做項目的時候需要使用到模糊查詢,但是后臺使用EF寫的 而不是ADO或者是Dapper,如果是這樣的話,我們就可以使用Sql語句直接進行模糊查詢 現在我們需要在LINQ中使用類似于模糊查詢 在EF中有兩個方法:StartsWith()和EndWith() StartsWith(): 在轉到定義時 我們可以看見,這個方…

android toast居中顯示_Android Toast 設置到屏幕中間,自定義Toast的實現方法,及其說明...

Android Toast用于在手機屏幕上向用戶顯示一條信息&#xff0c;一段時間后信息會自動消失。信息可以是簡單的文本&#xff0c;也可以是復雜的圖片及其他內容(顯示一個view)。1.簡單用法Toast.makeText(midlet.getApplicationContext(), "用戶名不能為空", Toast.LENG…

leetcode103. 二叉樹的鋸齒形層次遍歷(bfs)

給定一個二叉樹&#xff0c;返回其節點值的鋸齒形層次遍歷。&#xff08;即先從左往右&#xff0c;再從右往左進行下一層遍歷&#xff0c;以此類推&#xff0c;層與層之間交替進行&#xff09;。例如&#xff1a; 給定二叉樹 [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回…

LintCode Find the Weak Connected Component in the Directed Graph

原題鏈接在這里&#xff1a;http://www.lintcode.com/en/problem/find-the-weak-connected-component-in-the-directed-graph/ 題目&#xff1a; Find the number Weak Connected Component in the directed graph. Each node in the graph contains a label and a list of its…

簡單了解tengine

Tengine是由淘寶網發起的Web服務器項目。它在Nginx的基礎上&#xff0c;針對大訪問量網站的需求&#xff0c;添加了很多高級功能和特性。最終目標是打造一個高效、穩定、安全、易用的Web平臺。1、基本的HTTP服務器特性1.處理靜態文件&#xff0c;索引文件以及自動索引&#xff…

服務器創建多個dhcp服務_如何在15分鐘內創建無服務器服務

服務器創建多個dhcp服務by Charlee Li通過李李 如何在15分鐘內創建無服務器服務 (How to create a serverless service in 15 minutes) The word “serverless” has been popular for quite a while. When Amazon released the AWS Lambda service in 2015, many tools emerg…

php snoopy視頻教程,php的Snoopy類

用了兩天這個類&#xff0c;發現很好用。獲取請求網頁里面的所有鏈接&#xff0c;直接使用fetchlinks就可以&#xff0c;獲取所有文本信息使用fetchtext(其內部還是使用正則表達式在進行處理)&#xff0c;還有其它較多的功能&#xff0c;如模擬提交表單等。使用方法&#xff1a…

網頁解析 css

網頁解析 css轉載于:https://www.cnblogs.com/guozepingboke/p/10792298.html

如何看pg數據庫版本號_查看pg數據庫版本

PostgreSQL 基本命令鏈接&#xff1a;http://blog.itpub.net/28602568/viewspace-1841163/標題&#xff1a;PostgreSQL 基本命令作者&#xff1a;&#xff4c;ōττ&#xff52;&#xff59;©版權所有[文章允許轉載,但必須以鏈接方式注明源地址,否則追究法律責任.]安裝步…

leetcode1091. 二進制矩陣中的最短路徑(bfs)

在一個 N N 的方形網格中&#xff0c;每個單元格有兩種狀態&#xff1a;空&#xff08;0&#xff09;或者阻塞&#xff08;1&#xff09;。一條從左上角到右下角、長度為 k 的暢通路徑&#xff0c;由滿足下述條件的單元格 C_1, C_2, ..., C_k 組成&#xff1a;相鄰單元格 C_i …

lock和synchronized的同步區別與選擇

區別如下&#xff1a; 1. lock是一個接口&#xff0c;而synchronized是java的一個關鍵字&#xff0c;synchronized是內置的語言實現&#xff1b;&#xff08;具體實現上的區別在《Java虛擬機》中有講解底層的CAS不同&#xff0c;以前有讀過現在又遺忘了。&#xff09; 2. syn…

首頁顯示登陸用戶名php,首頁登錄后怎么在首頁顯示用戶名以及隱藏登錄框?

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓index.php&#xff1a;登錄頁面用戶名&#xff1a;密碼&#xff1a;沒有賬號&#xff1f;立即注冊——————————————————————————doaction.php&#xff1a;header("Content-type:text/html;charsetutf…

react中使用構建緩存_通過在React中構建Tic Tac Toe來學習ReasonML

react中使用構建緩存3. 7. 2018: UPDATED to ReasonReact v0.4.23. 7. 2018&#xff1a;更新為ReasonReact v0.4.2 You may have heard of Reason before. It’s a syntax on top of OCaml that compiles to both readable JavaScript code and to native and bytecode as well…

echart vue 圖表大小_vue里echarts自適應窗口大小改變

echarts的圖表提供了一個resize方法可以自適應屏幕窗口改變&#xff0c;而重新渲染圖表大小的功能。因此我們只要監聽瀏覽器的窗口改變的resize事件&#xff0c;再結合echarts的圖表&#xff0c;就可以實現我們想要的功能了。如果是單個圖表的情況的話用window.onresize myCha…

用js檢測文本框中輸入的是否符合條件并有錯誤和正確提醒

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>捕獲異常</title></head><script type"text/javascript">function my_func(){try{xdocument.getElementById("input_id").value;ale…

leetcode784. 字母大小寫全排列(回溯)

給定一個字符串S&#xff0c;通過將字符串S中的每個字母轉變大小寫&#xff0c;我們可以獲得一個新的字符串。返回所有可能得到的字符串集合。 示例: 輸入: S “a1b2” 輸出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”] 輸入: S “3z4” 輸出: [“3z4”, “3Z4”] 輸入: S…

Petapoco使用SQLite的異常問題

在DbProviderFactory 初始化時&#xff0c;報一個"System.Data.SQLite.SQLiteFactory”的類型初始值設定項引發異常。 解決&#xff1a;不光要引用System.Data.SQLite。還要把SQLite.Interop.dll添加到運行目錄下。轉載于:https://www.cnblogs.com/crazy29/p/7595552.html…

CPP函數調用的方法

相比于C語言中函數可以直接調用&#xff0c;CPP的函數由于命名存在隱式添加&#xff0c;因此需要通過一套流程才能調用&#xff1a; 1. 編碼中&#xff0c;使用extern "C" 定義一個C函數&#xff0c;返回獲取對象的指針&#xff1b;執行該函數時&#xff0c;獲得一個…

php 算法 二進制文件,關于PHP二進制流 逐bit的低位在前算法(詳解)_PHP教程

復制代碼 代碼如下:/******************************************************* 逐bit的低位在前算法* param $x* return int*/function reverse($x){$result 0;for($i 0; $i < 8; $i){$result ($result <> $i));}return $result & 0xff;}調用展示&#xff1a;…