1. 程式人生 > >一篇好文之Android文字軟鍵盤全解

一篇好文之Android文字軟鍵盤全解

已經有一個多月沒有寫文章了,當然,我沒失蹤,我還活著!因為換了新的工作環境,所以在接手專案的時候花了點時間……不為自己做過多借口,今後持續更新好內容(還是希望自己能周更)!
這篇文章最初是記錄一個全屏模式下輸入框被軟鍵盤覆蓋的問題,要求背景不動,輸入框上移!碰巧之後專案發版,有一點時間,就想著能不能將Android文字使用做一個總結!結合之前自己做的一些筆記,這篇文章就順利產出了!
其實換工作之後,我更希望能產出高質量的文章,所以我對於這篇文章的期待其實蠻高的,希望這篇文章能幫助所有開發者解決在Android開發過程中遇到的文字問題。當然,現在文章記錄的是自己遇到的一些問題(不是很全面),希望各位在Android開發中遇到各種關於文字類的問題可以給我留言,我們一起來討論,研究對應的解決方案,完善這篇文章及專案!

大家在學習使用Android文字軟鍵盤內容的時候遇到什麼問題,歡迎在我的公眾號aserbao給我留言,無償服務!同時,歡迎大家來加入微信群二維碼討論群,一起討論Android開發技術!群二維碼定時在我公眾號更新!

在這裡插入圖片描述

專案效果

在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述

TextView的基本使用

TextView的基本屬性

常用的屬性:

<TextView
        android:text="@string/long_text"
        android:textSize="10sp"
        android:textColor="@color/black"
        android:shadowRadius="8"
        android:shadowColor="@color/black70"
        android:shadowDy="4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

下面這些基本包含TextView的所有屬性,裡面很多屬性大多數情況下我們都使用不到,可以稍微瞭解下,可以直接跳過屬性列表!

屬性 作用
android:text 設定顯示文字.
android:textAppearance 設定文字外觀
android:textColor 設定文字顏色
android:textColorHighlight 被選中文字的底色,預設為藍色
android:textColorHint 設定提示資訊文字的顏色,預設為灰色。與hint一起使用。
android:textColorLink 文字連結的顏色.
android:textScaleX 設定文字之間間隔,預設為1.0f。
android:textSize 設定文字大小,推薦度量單位”sp”,如”15sp”
android:textStyle 設定字形[bold(粗體) 0, italic(斜體) 1, bolditalic(又粗又斜) 2] 可以設定一個或多個,用“|”隔開
android:typeface 設定文字字型
android:height 設定文字區域的高度,支援度量單位:px(畫素)/dp/sp/in/mm(毫米)
android:maxHeight 設定文字區域的最大高度
android:minHeight 設定文字區域的最小高度
android:width 設定文字區域的寬度,支援度量單位:px(畫素)/dp/sp/in/mm(毫米),與layout_width 的區別看這裡。
android:shadowColor 指定文字陰影的顏色,需要與shadowRadius一起使用。
android:shadowDx 設定陰影橫向座標開始位置。
android:shadowDy 設定陰影縱向座標開始位置。
android:shadowRadius 設定陰影的半徑。一般設定為5.0的效果比較好。
android:singleLine 設定單行顯示。如果和layout_width一起使用,當文字不能全部顯示時,後面用“…”來表示。如android:text=”test_ singleLine “
android:singleLine=”true” android:layout_width=”20dp” 將只顯示“t…”。如果不設定singleLine或者設定為false,文字將自動換行
android:cursorVisible 設定游標為顯示/隱藏,預設顯示。
android:digits 設定允許輸入哪些字元。如“1234567890.±*/% ()”
android:drawableTop\Bottom\Left\Right 在text的上、下、左、右方輸出一個drawable
android:drawablePadding 設定text與drawable(圖片)的間隔
android:editable 設定是否可編輯。
android:editorExtras 設定文字的額外的輸入資料。
android:ellipsize 設定當文字過長時,該控制元件該如何顯示。有如下值設定:”start”—-省略號顯示在開頭;”end” ——省略號顯示在結尾;”middle”—-省略號顯示在中間;”marquee” ——以跑馬燈的方式顯示(動畫橫向移動)
android:freezesText 設定儲存文字的內容以及游標的位置。
android:gravity 設定文字位置,設定成“center”,文字將居中顯示。
android:hintText 為空時顯示的文字提示資訊,可通過textColorHint設定提示資訊的顏色。此屬性在 EditView中使用,但是這裡也可以用。
android:imeOptions 附加功能,設定右下角IME動作與編輯框相關的動作,如actionDone右下角將顯示一個“完成”,而不設定預設是一個回車符號。這個在EditView中再詳細說明,此處無用。
android:imeActionId 設定IME動作ID
android:imeActionLabel 設定IME動作標籤
android:includeFontPadding 設定文字是否包含頂部和底部額外空白,預設為true。
android:inputMethod 為文字指定輸入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin
android:inputType 設定文字的型別,用於幫助輸入法顯示合適的鍵盤型別。在EditView中再詳細說明,這裡無效果。
android:linksClickable 設定連結是否點選連線,即使設定了autoLink。
android:marqueeRepeatLimit 在ellipsize指定marquee的情況下,設定重複滾動的次數,當設定marquee_forever時表示無限次。
android:ems 設定TextView的寬度為N個字元的寬度。這裡測試為一個漢字字元寬度
android:maxEms 設定TextView的寬度為最長為N個字元的寬度。與ems同時使用時覆蓋ems選項。
android:minEms 設定TextView的寬度為最短為N個字元的寬度。與ems同時使用時覆蓋ems選項。
android:maxLength 限制顯示的文字長度,超出部分不顯示。
android:lines 設定文字的行數,設定兩行就顯示兩行,即使第二行沒有資料。
android:maxLines 設定文字的最大顯示行數,與width或者layout_width結合使用,超出部分自動換行,超出行數將不顯示。
android:minLines 設定文字的最小行數,與lines類似。
android:lineSpacingExtra 設定行間距。
android:lineSpacingMultiplier 設定行間距的倍數。如”1.2”
android:numeric 如果被設定,該TextView有一個數字輸入法。此處無用,設定後唯一效果是TextView有點選效果,此屬性在EdtiView將詳細說明。
android:password 以小點”*”顯示文字
android:phoneNumber 設定為電話號碼的輸入方式。
android:privateImeOptions 設定輸入法選項,此處無用,在EditText將進一步討論。
android:scrollHorizontally 設定文字超出TextView的寬度的情況下,是否出現橫拉條。
android:selectAllOnFocus 如果文字是可選擇的,讓他獲取焦點而不是將游標移動為文字的開始位置或者末尾位置。 需要再EditText中設定。
android:maxWidth 設定文字區域的最大寬度
android:minWidth 設定文字區域的最小寬度

圖文混排的三種實現方式

1. drawableTop,DrawableBottom,DrawableLeft,drawableRight

<TextView
            android:id="@+id/one_pictxt_tv"
            android:drawableLeft="@drawable/emoji_00"
            android:drawableRight="@drawable/emoji_01"
            android:drawableBottom="@drawable/emoji_02"
            android:drawableTop="@drawable/emoji_03"
            android:text="第一種方式:\n通過drawableLeft來實現\n上下左右中間文字"
            style="@style/picTxt_tv_style"
             />

2. 通過ImageSpan或者DynamicDrawableSpan實現

SpannableString dynamicDrawableSpan = new SpannableString("DynamicDrawableSpan");
        DynamicDrawableSpan drawableSpan =
                new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
                    @Override
                    public Drawable getDrawable() {
                        Drawable d = getResources().getDrawable(R.drawable.emoji_00);
                        d.setBounds(0, 0, 150, 150);
                        return d;
                    }
                };
        DynamicDrawableSpan drawableSpan2 = new DynamicDrawableSpan(
                DynamicDrawableSpan.ALIGN_BOTTOM) {
            @Override
            public Drawable getDrawable() {
                Drawable d = getResources().getDrawable(R.drawable.emoji_01);
                d.setBounds(0, 0, 150, 150);
                return d;
            }
        };
        dynamicDrawableSpan.setSpan(drawableSpan, 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        dynamicDrawableSpan.setSpan(drawableSpan2, 7, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mDynamicDrawableSpanTv.setText(dynamicDrawableSpan);



        SpannableString imageSpan = new SpannableString("ImageSpan");
        Drawable d = getResources().getDrawable(R.drawable.emoji_02);
        d.setBounds(0, 0, 150, 150);
        imageSpan.setSpan(new ImageSpan(d), 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mIamgeSpanTv.setText(imageSpan);

3. 通過給TextView設定Html內容

如果要包含圖片的話需要重寫一個類實現ImageGetter介面並重寫getDrawable方法,具體實現可以下載底部專案原始碼!

mThreePictxtTv.setText(Html.fromHtml("點選我,帶你到HtmlTextActivity中去<font color= '#ff0000'>textView通過Html實現圖文混排</font> 點選這一段"));

帶圖片的html的設定:

String g = "<html>" +"<head>" + "</head>" +"<body style=\"text-align: justify\">" +
"\t<h3>Android效能優化之APK瘦身詳解(瘦身73%)</h3>" +"\t<P>公司專案在不斷的改版迭代中,程式碼在不斷的累加,終於apk包不負重負了,已經到了八十多M了。可能要換種方式表達,到目前為止沒有正真的往外推過,一直在內部執行7天討論需求,5天程式碼實現的階段。你在寫上個版本的內容,好了,下個版本的更新內容已經定稿了。基於這種快速開發的現狀,我們app優化前已經有87.1M了,包大了,運營說這樣轉化不高,只能好好搞一下咯。優化過後包大小為23.1M(優化了73%,不要說我標題黨)。好了好了,我要闡述我的apk超級無敵魔鬼瘦身之心得了。</p>" +"" +"\t<img src=\"imgs/0.png\" style=\"width: 100%;\" />" + "" + "</body>" +"</html>";
   mHtmlTv.setText(Html.fromHtml(htmlContent, new MImageGetter(mHtmlTv,HtmlTextActivity.this),null));

public class MImageGetter implements ImageGetter {
		Context c;
	    public MImageGetter(TextView text, Context c) {
	        this.c = c;
	    }
	 public Drawable getDrawable(String source) {
		    Drawable drawable = null;
		    InputStream is = null;
			try {
				is = c.getResources().getAssets().open(source);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
            try {
                TypedValue typedValue = new TypedValue();
                typedValue.density = TypedValue.DENSITY_DEFAULT;
                drawable = Drawable.createFromResourceStream(null, typedValue, is, "src");
                DisplayMetrics dm = c.getResources().getDisplayMetrics();
        		int dwidth = dm.widthPixels-10;//padding left + padding right 
        		float dheight = (float)drawable.getIntrinsicHeight()*(float)dwidth/(float)drawable.getIntrinsicWidth();
        		int dh = (int)(dheight+0.5);
        		int wid = dwidth;
                int hei = dh;
                drawable.setBounds(0, 0, wid, hei);
                return drawable;
            } catch (Exception e) {
            	System.out.println(e);
                return null;
            }   
	    }
}

EditText的基本使用

1. EditText的基本屬性

 <EditText
                    android:textIsSelectable="true"     //文字是否可選,複製貼上剪輯,在TextVew中使用,在EditText中使用此屬性將收不到軟鍵盤輸入內容
                    android:id="@+id/pop_select_label_et"
                    android:layout_weight="1"
                    android:paddingLeft="25dp"
                    android:background="@drawable/find_num_tv_bg"//@null 取消下劃線
                    android:hint="輸入話題"
                    android:maxLength="30"
                    android:textColorHint="@color/white"
                    android:textColor="@color/white"
                    android:singleLine="true"
                    android:imeOptions="actionSearch"//軟鍵盤右下方修改為搜尋
                    android:layout_width="0dp"
                    android:textCursorDrawable="@drawable/text_view_cursor" //修改游標的顏色
                    android:textSize="15sp"
                    android:cursorVisible="false"//是否顯示游標
                    android:focusable="true"//是否可以focu
                    android:layout_height="match_parent"
                    />

1. imeOption屬性

imeOptions:值:

  • actionDone:完成,對應常量EditorInfo.IME_ACTION_DONE
  • actionSend :傳送,對應常量EditorInfo.IME_ACTION_SEND
  • actionSearch 搜尋,對應常量EditorInfo.IME_ACTION_SEARCH
  • actionGo 去往,對應常量EditorInfo.IME_ACTION_GO
  • actionNone 沒有動作,對應常量EditorInfo.IME_ACTION_NONE
  • actionUnspecified 未指定,預設,對應常量EditorInfo.IME_ACTION_UNSPECIFIED.
  • actionNext 下一個,對應常量EditorInfo.IME_ACTION_NEXT

2. inputType屬性

android:inputType="phone" //電話號碼
    android:inputType="none" 
    //文字型別,多為大寫、小寫和數字符號。 
    android:inputType="text"  
    android:inputType="textCapCharacters" //字母大寫 
    android:inputType="textCapWords" //首字母大寫 
    android:inputType="textCapSentences" //僅第一個字母大寫 
    android:inputType="textAutoCorrect" //自動完成 
    android:inputType="textAutoComplete" //自動完成 
    android:inputType="textMultiLine" //多行輸入 
    android:inputType="textImeMultiLine" //輸入法多行(如果支援) 
    android:inputType="textNoSuggestions" //不提示 
    android:inputType="textUri" //網址 
    android:inputType="textEmailAddress" //電子郵件地址 
    android:inputType="textEmailSubject" //郵件主題 
    android:inputType="textShortMessage" //短訊 
    android:inputType="textLongMessage" //長資訊 
    android:inputType="textPersonName" //人名 
    android:inputType="textPostalAddress" //地址
    android:inputType="textPassword" //密碼 
    android:inputType="textVisiblePassword" //可見密碼
    android:inputType="textWebEditText" //作為網頁表單的文字 
    android:inputType="textFilter" //文字篩選過濾 
    android:inputType="textPhonetic" //拼音輸入 

    //數值型別 
    android:inputType="number" //數字 
    android:inputType="numberSigned" //帶符號數字格式 
    android:inputType="numberDecimal" //帶小數點的浮點格式 
    android:inputType="datetime" //時間日期 
    android:inputType="date" //日期鍵盤 
    android:inputType="time" //時間鍵盤

2. 監聽軟鍵盤右下角按鍵

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                switch (actionId){
                    case EditorInfo.IME_ACTION_SEARCH:
                        break;
                    case EditorInfo.IME_ACTION_DONE:
                        break;
                    case EditorInfo.IME_ACTION_SEND:
                        break;
                    case EditorInfo.IME_ACTION_GO:
                        break;
                    case EditorInfo.IME_ACTION_NONE:
                        break;
                    case EditorInfo.IME_ACTION_NEXT:
                        break;
                    case EditorInfo.IME_ACTION_UNSPECIFIED:
                        break;
                }
                return false;
            }
        });

3. 設定imeOption不生效的解決辦法

設定imeOption無效:需要將singleLine設定為true或者 將inputType設定為text

2. 修改EditText下劃線的顏色

//1. 通過修改colorAccent屬性來修改下劃線顏色,此方法會全域性修改
 <item name="colorAccent">@color/colorWhite80</item>
   
//2. 通過修改EditText的style來修改下劃線顏色
<style name="MyEditText2" parent="Theme.AppCompat.Light">
        <item name="colorControlNormal">@color/colorWhite80</item> //控制元件預設的顏色
        <item name="colorControlActivated">@color/colorWhite50</item> // 控制元件被啟用的顏色
</style>

3. 控制輸入框最多輸入20個字元(10個漢字,20個英文字元)

Android原生計算方法沒有漢字和英文字元的區分,所以當產品有這個需求的時候,只能通過過濾計算去限制輸入!這裡提供兩種方案:

1. 通過TextWatcher來監聽輸入字串內容進行過濾

editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                int charSequenceCount = countChineseChar(s);
                if (s.length() + charSequenceCount > StaticFinalValues.MAX_CHAR_NUM_SELECT) {
                    CharSequence text = s.subSequence(0, s.length() - 1);
                    editText.setText(text);
                editText.setSelection(text.length());//游標跳最後
                    if(System.currentTimeMillis() - mLastTime > 500) {
                        Toast.makeText(mContext, "輸入不能多於" + String.valueOf( StaticFinalValues.MAX_CHAR_NUM_SELECT) +"字元", Toast.LENGTH_SHORT).show();
                        mLastTime = System.currentTimeMillis();
                    }
                    return;
                }
            }
        });
       
        /**
     * 計算中文字元
     *
     * @param sequence
     * @return
     */
    public static int countChineseChar(CharSequence sequence) {
        if (TextUtils.isEmpty(sequence)) {
            return 0;
        }
        int charNum = 0;
        for (int i = 0; i < sequence.length(); i++) {
            char word = sequence.charAt(i);
            if (UiUtils.isChineseChar(word)) {//中文
                charNum++;
            }
        }
        return charNum;
    }
    /**
     * 判斷是否是中文
     * @param c
     * @return
     */
    public static boolean isChineseChar(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }

2. 通過實現InputFileter來過濾,中文算兩個字元,英文算一個

public class MaxLengthEditText extends AppCompatEditText {
    public MaxLengthEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLength(attrs,context);
    }
    public MaxLengthEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initLength(attrs,context);
    }
    private void initLength(AttributeSet a, Context context) {
        //名稱空間(別告訴我不熟悉)
        String namespace = "http://schemas.android.com/apk/res/android";
        //獲取屬性中設定的最大長度
        int maxLength = a.getAttributeIntValue(namespace, "maxLength", -1);
        //如果設定了最大長度,給出相應的處理
        if (maxLength > -1) {
            setFilters(new InputFilter[]{new MaxLengthEditText.MyLengthFilter(maxLength,context)});
        }
    }
    /**
     * 從原始碼中複製出來的
     * 來源:InputFilter.LengthFilter
     * 這裡只是添加了一句話:
     *              Toast.makeText(context, "字數不能超過" + mMax, Toast.LENGTH_SHORT).show();
     *
     * This filter will constrain edits not to make the length of the text
     * greater than the specified length.
     */
    class MyLengthFilter implements InputFilter {

        private final int mMax;
        private Context context;

        public MyLengthFilter(int max, Context context) {
            mMax = max;
            this.context = context;
        }

        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                                   int dstart, int dend) {
            int keep = 0;
            for (int i = 0; i < dest.length(); i++) {
                char charAt = dest.charAt(i);
                //32-122包含了空格,大小寫字母,數字和一些常用的符號,
                //如果在這個範圍內則算一個字元,
                //如果不在這個範圍比如是漢字的話就是兩個字元
                if (charAt >= 32 && charAt <= 122) {
                    keep++;
                } else {
                    keep += 2;
                }
            }
            if(keep <= mMax){
                 return source.subSequence(start, source.length());
            }else{
                 Toast.makeText(mContext, "輸入少一點,太多了", Toast.LENGTH_SHORT).show();
                return "";
            }
        }
        /**
         * @return the maximum length enforced by this input filter
         */
        public int getMax() {
            return mMax;
        }
    }
}

4. 判斷軟鍵盤輸入的是否有表情

若需求宣告,表情只能算一個字元,這時候就需要在輸入後進行判斷:

            @Override
            public void afterTextChanged(Editable s) {
                String s1 = s.toString();
                char[] sC = new char[s1.length()];
                s1.getChars(0,s1.length(),sC,0);
                for (char c : sC) {
                    Log.e(TAG, "afterTextChanged: "+ isEmojiCharacter(c));
                }
            }
                
  private static boolean isEmojiCharacter(char codePoint) {
        return !((codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD) || ((codePoint >= 0x20) && codePoint <= 0xD7FF))|| ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }               

軟鍵盤全解

Activity的SoftInputMethod引數講解

屬性 作用
stateUnspecified 未指定狀態,系統預設採用的互動方式,預設不彈出軟鍵盤,但是對於輸入框介面有滾動佈局時且EditText獲得焦點時,軟鍵盤彈出
stateUnchanged 狀態不改變 ,當前介面的軟鍵盤是否顯示,取決於上一個Activity軟鍵盤的狀態
stateHidden 軟鍵盤一定是隱藏
stateAlwaysHidden 軟鍵盤一定是隱藏,暫時沒發現和stateHidden有啥區別
stateVisible 設定為這個屬性,可以將軟鍵盤召喚出來,即使在介面上沒有輸入框的情況下也可以強制召喚出來
stateAlwaysVisible 軟鍵盤預設顯示,當給AActivity設定stateVisible屬性時,從當前AActivity跳轉到BActivity,軟鍵盤隱藏,再從BActivity返回AActivity,軟鍵盤不顯示!當設定stateAlwaysVisible屬性時,跳轉後的返回軟鍵盤依舊顯示!
adjustUnspecified 系統預設屬性,預設adjustPan的效果!如果在設定這個屬性之前設定過adjustResize,則會是adjustResize的效果!如果上一次設定為adjustPan,再設定為adjustUnspecified,則會是adjustPan的效果!
adjustResize 設定這個屬性,當前Activity總會給軟鍵盤預留顯示空間,輸入框被彈出軟鍵盤覆蓋掉,有兩種情況:1. 有滾動佈局,其他佈局不移動且大小不改變,輸入框移動到軟鍵盤上面 2. 無滾動佈局,通過修改其他佈局的大小達到輸入框移動到軟鍵盤的效果
adjustPan 設定這個屬性,Activity不會預留軟鍵盤顯示空間,而是通過佈局移動來保證輸入框不被軟鍵盤覆蓋!只要輸入框被軟鍵盤覆蓋,就會通過移動整個佈局來達到顯示輸入框的效果!
注意 當Activity設定全屏後,adjustResize和adjustPan沒有任何區別!無論是否有滾動佈局,Activity都會往上移動

軟鍵盤的隱藏,顯示,及判斷是否顯示工具類

public class AppKeyBoardMgr {
    /**
     * 開啟軟鍵盤
     * @param mEditText  輸入框
     * @param mContext   上下文
     */
    public static void openKeybord(EditText mEditText, Context mContext)
    {
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    }

    /**
     * 顯示輸入法
     * @param mAct activity
     */
    public static void showInputMethod(final Activity mAct) {
        View v = mAct.getCurrentFocus();
        if (null == v) {
            return;
        }
        ((InputMethodManager) mAct.getSystemService(Activity.INPUT_METHOD_SERVICE)).showSoftInput(v, 0);
    }

    /**
     * 強制顯示輸入法鍵盤
     */
    public static void showKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
                edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.showSoftInput(edittext, InputMethodManager.SHOW_FORCED);
    }
    
    /**
     * 關閉軟鍵盤
     * @param mEditText 輸入框
     * @param mContext  上下文
     */
    public static void closeKeybord(EditText mEditText, Context mContext)
    {
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
    }
    /**
     * 強制隱藏輸入法鍵盤
     */
    public static void hideKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
                edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager.isActive()) {
            inputMethodManager.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
        }
    }
    
    /**
     * 隱藏輸入法
     * @param mAct activity
     */
    public static void hideInputMethod(Activity mAct) {
        try {// hide keybord anyway
            View v = mAct.getWindow().getCurrentFocus();
            if (v != null) {
                InputMethodManager imm = (InputMethodManager) mAct.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        } catch (Exception e) {
        }
    }
    /**
     * 通過定時器強制隱藏虛擬鍵盤
     */
    public static void TimerHideKeyboard(final View v) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm.isActive()) {
                    imm.hideSoftInputFromWindow(v.getApplicationWindowToken(),0);
                }
            }
        }, 10);
    }

    /**
     * 切換軟鍵盤的狀態
     * 如當前為收起變為彈出,若當前為彈出變為收起
     */
    public static void toggleKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
            edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }
    /**
     * 輸入法是否顯示
     */
    public static boolean isKeybord(EditText edittext) {
        boolean bool = false;
        InputMethodManager inputMethodManager = (InputMethodManager)
            edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager.isActive()) {
            bool = true;
        }
        return bool;
    }
}

軟鍵盤彈出監聽及高度獲取

Android系統沒有對軟鍵盤做特別的開放監聽介面,一般情況下我們可以通過佈局的addOnGlobalLayoutListener介面來獲取軟鍵盤是否顯示的監聽!
提別提醒:如果設定了屬性adjustNothing,佈局沒有任何改變,addOnGlobalLayoutListener這個監聽是不會有回撥的!

特別說明:下面計算軟鍵盤高度通過兩種方式來獲取,為了相容,這裡採用兩種方式取最小值來獲取軟鍵盤高度,一種是通過反射系統方法getInputMethodWindowVisibleHeight()方法來獲取軟鍵盤高度,一種通過計算佈局顯示高度來確認軟鍵盤高度!

 //拿到當前XML檔案的根佈局
        mChildContent = (FrameLayout) findViewById(android.R.id.content);
        //監聽當前View的狀態,進行通知回撥,即"軟鍵盤彈出""
        View childew = mChildContent.getChildAt(0);
        childew.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
            	//反射獲取
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                int injectSoftHeight = 0;
                try {
                    Method method = inputMethodManager.getClass().getDeclaredMethod("getInputMethodWindowVisibleHeight", null);
                    method.setAccessible(true);
                    injectSoftHeight = (Integer) method.invoke(inputMethodManager, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
				//佈局顯示高度差來計算
                View decorView = getWindow().getDecorView();
                Rect r = new Rect();
                //r will be populated with the coordinates of your view that area still visible.
                decorView.getWindowVisibleDisplayFrame(r);
                int rootHeight = decorView.getRootView().getHeight();
                int rH = r.bottom - r.top;
                int measureDVHeight = rootHeight - rH;

                if (injectSoftHeight > 200) {
                    mMeasureSoftKBHeight = injectSoftHeight < measureDVHeight ? injectSoftHeight : measureDVHeight;
                } else if (injectSoftHeight <= 200) {
                    mMeasureSoftKBHeight = measureDVHeight;
                }
              
                if (mLastHeight != mMeasureSoftKBHeight) {
                    if (mMeasureSoftKBHeight > 200) {//200這個值視情況而定,目前設定這個值沒有出現相容問題
                        //軟鍵盤顯示
                    } else {
                        //軟鍵盤隱藏
                    }
                    mLastHeight = mMeasureSoftKBHeight;
                }
            }
        });

軟鍵盤常見問題

非全屏模式下軟鍵盤覆蓋輸入框,做背景不動,軟鍵盤上移效果

這種情況,直接通過設定帶滾動佈局,設定adjustResize屬性就可以實現效果

全屏模式下軟鍵盤覆蓋輸入框的問題,做背景不動,軟鍵盤上移效果

1. 第一種思路:獲取軟鍵盤高度後修改父佈局的高度

思路介紹圖

思路參考於:AndroidBug5497Workaround
在這裡插入圖片描述

程式碼實現
//思路參考於:AndroidBug5497Workaround
public class AndroidSoftBoardAdjustHeightUtil {

    public static void assistActivity(Activity activity) {
        new AndroidSoftBoardAdjustHeightUtil(activity);  
    }  
  
    private View mChildOfContent;
    private int                      usableHeightPrevious;  
    private FrameLayout.LayoutParams frameLayoutParams;
  
    private AndroidSoftBoardAdjustHeightUtil(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;  
            //排除其他View引起的變化,專注軟鍵盤變化  
            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);  
        //r.top : 標題欄的高度  
        //螢幕高度-r.bottom : 軟鍵盤的高度  
        //可用高度(全屏模式) : rect.bottom  
        //可用高度(非全屏模式) : rect.bottom - rect.top  
        return (r.bottom - r.top);// 全屏模式下: return r.bottom  
    }  
  
}  

2. 第二種思路:通過新增佔位圖的方式將輸入框上移

思路介紹圖

由於第一種方式會有相容問題,而且軟鍵盤彈出的時候部分手機會出現閃爍現象!

  1. 通過設定下圖中的PlaceholderView的Visible和Gone來控制EditText的高度
    在這裡插入圖片描述
程式碼
  1. 在輸入框onTouch事件的時候將佔位檢視顯示出來,防止閃爍問題
  2. 在監聽到軟鍵盤彈出之後,通過檢視的偏移高度和反射呼叫getInputMethodWindowVisibleHeight獲取軟鍵盤高度取最小值!(為了適配手機虛擬鍵盤高度計算,本人自測,任何一種方式都不能相容到所有手機,最終通過取兩種計算結果下的最小值來解決這個問題!)
 private void initCheckKeyBoardIsShow(final EditText editText) {
        editText.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                editText.setCursorVisible(true);
                mPlaceholderTv.setVisibility(View.VISIBLE);
                return false;
            }
        });
        //拿到當前XML檔案的根佈局
        mChildContent = (FrameLayout) findViewById(android.R.id.content);

        //監聽當前View的狀態,進行通知回撥,即"軟鍵盤彈出""
        View childew = mChildContent.getChildAt(0);
        childew.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                int injectSoftHeight = 0;
                try {
                    Method method = inputMethodManager.getClass().getDeclaredMethod("getInputMethodWindowVisibleHeight", null);
                    method.setAccessible(true);
                    injectSoftHeight = (Integer) method.invoke(inputMethodManager, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                View decorView = getWindow().getDecorView();
                Rect r = new Rect();
                decorView.getWindowVisibleDisplayFrame(r);
                int rootHeight = decorView.getRootView().getHeight();
                int rH = r.bottom - r.top;
                int measureDVHeight = rootHeight - rH;
                
                if (injectSoftHeight > 200) {
                    mMeasureSoftKBHeight = injectSoftHeight < measureDVHeight ? injectSoftHeight : measureDVHeight;
                } else if (injectSoftHeight <= 200) {
                    mMeasureSoftKBHeight = measureDVHeight;
                }
                if (mLastHeight != mMeasureSoftKBHeight) {
                    if (mMeasureSoftKBHeight > 200) {
                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mPlaceholderTv.getLayoutParams();
                        int result = 0;
                        result = mMeasureSoftKBHeight;
                        layoutParams.height = result;
                        mPlaceholderTv.setLayoutParams(layoutParams);
                        mPlaceholderTv.postInvalidate();
                        setRecordBtnMargain(mMeasureSoftKBHeight);
                    } else {
                        setRecordBtnMargain(0);
                        mNewStoryEt.setCursorVisible(false);
                        mPlaceholderTv.setVisibility(View.GONE);
                    }
                    mLastHeight = mMeasureSoftKBHeight;
                }
            }
        });
    }

專案地址

AserbaosAndroid
aserbao的個人Android總結專案,希望這個專案能成為最全面的Android開發學習專案,這是個美好的願景,專案中還有很多未涉及到的地方,有很多沒有講到的點,希望看到這個專案的朋友,如果你在開發中遇到什麼問題,在這個專案中沒有找到對應的解決辦法,希望你能夠提出來,給我留言或者在專案github地址提issues,我有時間就會更新專案沒有涉及到的部分!專案會一直維護下去。當然,我希望是Aserbao’sAndroid 能為所有Android開發者提供到幫助!也期望更多Android開發者能參與進來,只要你熟悉Android某一塊,都可以將你的程式碼pull上分支供大家學習!

總結

這篇文章是新環境下的第一篇文章,斷斷續續就這麼過了一週了,當時是關於軟鍵盤的問題,全屏顯示情況下,軟鍵盤的顯示,背景不移動!為什麼到現在才發,主要有下面兩方面原因:

  1. 希望今後所有的關於哪一方面的問題都能在一篇文章裡面找到!
  2. 我希望自己的每篇文章內容是有價值的,無論是對別人還是自己,能夠記錄下一個系列下自己踩過的所有坑!

這篇文章最後定義為《初級》,意為所有常見開發中會遇到的文字問題都會在這篇文章中同步更新,後面會有兩篇《中級》《高階》,中級會講自定義軟鍵盤的內容,高階會分析Andriod軟體軟鍵盤的整體實現架構!目前的思路是這樣的!

如果你在Android開發的過程中遇到文本系列的問題在文章中找不到對應的解決辦法,可以在文章底部或者我的公眾號aserbao給我留言!我會和你一起探討研究問題並持續更新文章!

百密難免一疏,文章純手打,若有出錯之處,還請各位幫忙指出!若文章內容對各位有幫助,幫忙留言點個贊,給作者一絲鼓勵,謝謝!

相關推薦

Android文字鍵盤

已經有一個多月沒有寫文章了,當然,我沒失蹤,我還活著!因為換了新的工作環境,所以在接手專案的時候花了點時間……不為自己做過多借口,今後持續更新好內容(還是希望自己能周更)! 這篇文章最初是記錄一個全屏模式下輸入框被軟鍵盤覆蓋的問題,要求背景不動,輸入框上移!碰

Android資料庫GreenDao的完全解析

今日科技快訊 小米近日稱,財政部此次公告的檢查為2017年財政部會計監督檢查,是針對2016年的會計資訊質量進行的檢查。公司存在部分費用攤銷核算錯誤、對外贈送商品未作為視同銷售行為申報繳稅、報銷發票管理不規範、費用管理制度不完善等問題。以上問題均已整改完成,並獲得財政部

Android 呼叫C程式碼及生成除錯so庫

不靠譜的朱先生又來了,今天是週五,我又出現了!好了,不為自己多解釋,上週沒發文章,其實我寫了,只是沒有發出來而已……機智ovo。 上週寫的文章是關於GreenDao全面解析,其實當時是想寫一個關於資料庫的系列文章,後來一共就寫了兩篇,SQlite全面解析和GreenDao全面解析。至

Android資料庫 SQLite解析

這篇文章是資料庫系列篇文章的第一篇,主要講Android Sqlite資料庫儲存,後面陸續出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何關於Android中SQLite的問題,都可以直接在我的文章底部留言,或者直接在我

異步原創征集令,本書!

Markdown 活動征集 點擊上方“異步社區”,選擇“置頂公眾號”技術幹貨,第一時間送達各位異步社區的小夥伴和大神,大家好!我是你們的異步君,就是一直被你們吐槽的,躲在異步客服後面的異步君。對,尤其最近新版上線後,被吐槽更激烈的異步君!之前大家一致吐槽異步君:想在異步社區寫個技術文章都難啊!社區編輯

推薦《佛教真像大家所認為的那樣消極嗎?》

推薦一篇好文《佛教真像大家所認為的那樣消極嗎?》   差不多一年前關注了一個叫“學佛導航”的公眾號,它都是發表一些“雞湯文”與“養生文”,譬如什麼什麼菩薩過生日啦,做了什麼好事又有福報啦云云。雖然鄙人從小對佛教文化耳融目染,家中不僅大部分人對於佛教十分虔誠而且還有親戚是很專業

轉發:36氪翻譯自medium的文章: 讀書沒有 KPI:為什麼堅持“年讀 100 本書”沒用?

你只是為了達成所謂的數量目標而讀書。 編者按:讀書本是一項安靜、緩慢的活動,但隨著現代社會節奏的加快,資訊科技的廣泛普及,讀書這一行為模式也開始發生了變化。越來越多的人開始碎片化閱讀,並且越來越多的文章推崇速讀或者是一年讀多少本書才能實現自我提升等觀點。Jotform 創始人 Aytekin Tank

就應該有一個的標題

老板 好的 字型 若是 hone 也不會 必須 疑問 公司 無論是什麽樣的軟文,讀者群體接觸的第一眼就是標題,一個好的標題,那麽這篇文章基本就成功了一半,如若是標題並不能吸引人的眼球,那麽即使文章寫得再好,會點進去的讀者也不會多。 以下是維貝工作室根據多年軟文推廣營銷的經驗

移動APP測試基礎效能測試流程-

https://www.oschina.net/question/2562975_2218004 評估App的時間和空間特性 : 極限測試:在各種邊界壓力情況下,如電池、儲存、網速等,驗證App是否能正確響應。 --記憶體滿時安裝App --執行App時手機斷

多執行緒程式設計Linux環境下的多執行緒()——

一、Linux環境下的執行緒   相對於其他作業系統,Linux系統核心只提供了輕量級程序的支援,並未實現執行緒模型。Linux是一種“多程序單執行緒”的作業系統,Linux本身只有程序的概念,而其所謂的“執行緒”本質上在核心裡仍然是程序。      程序是資源分配的單位,同一程序中的多個執行緒共享該程序的

僅僅是吐槽自己的文字

多個 補丁 通知 賽後 下午 快的 不足 吐槽 退役 下午還沒有收到愛奇藝的決賽通知,猜著也過不了的。。 省賽晚上打的復賽。 第一題是搜索吧?寫不好,最後發現居然是定義了多個變量,導致搜索邊界出了問題 第二題單調棧?肉眼可見,但是就是寫不對!只過了80個點 第三題甚至都沒

將課程作業01的設計思想、程序流程圖、源程序代碼和結果截圖整理成

package static 技術分享 整理 public out 計算 mage 數字 1.程序設計思想 先讓用戶輸入要計算的數字的個數,然後讓用戶輸入這幾個數,將字符型轉化為整數,然後求和,最後輸出所求得的和即可。 2.程序流程圖 3.源程序代碼 pack

將課程作業01、02、03的設計思想、源程序代碼和結果截圖整理成。。

top exception 漢諾塔 一個數 resource valueof val 作業 回文數 信1605-3 於丁一 20163578 使用組合數公式利用n!來計算 設計思想:首先要判斷一個數的階乘如何表達,然後調用方法用組合數公式,最後求出組合數。 packag

2018年3月19日推薦文章精選 “打盡”

文章精選 精選 好文 區塊鏈,工作證明(POW)代碼+原理 golang版剖析 作者:64180190簡介:在本文中,我們將討論哈希值。哈希是獲取指定數據的哈希值的過程。 哈希值是對其計算的數據的唯一表示。 哈希函數是一個獲取任意大小的數據並產生固定大小的哈希的函數。 以下是哈希的一些主要功能:

通過PHP把英文件中所有單詞的首字母轉為大寫

index.php程式碼如下:     <?php     header("Content-type: text/html; charset=utf8");      &n

如何選擇用的換IP件?

人員 設置 new 手動 ip地址 出現 www. news 好的 信息大爆炸的時代,找到機會更是容易的很,而上網工具要好,才會大家的工作更加有效率。網絡營銷工作中推廣是一種手段,而要是沒有好的工具就何談容易,網頁換IP軟件也是很多,選擇一款好用又方便的工具才能帶來事半功倍

網上看中文章,無法複製?不要著急,一個程式碼,教你搞定!

不知道大家有沒有和我一樣的苦惱,在網上看到自己很感興趣,很喜歡的文章,卻不能複製!真的很討厭! 後來我學會了一個小技巧——一個程式碼,即可複製你看中的任何內容! 你想學習嗎?想的話,就接著往下看喲! 應用舉例: 如圖,這篇文章想要下載,就需要註冊登入才可以。 其

CSDN如何轉載的文章

轉載CSDN部落格步驟: 1.CSDN部落格頁面右鍵,點選【檢查】 點選檢查後,頁面右側出現html程式碼,如下圖 2.如果需要轉載全文,則在html程式碼下側點選選中article_content 即可,會在程式碼框中自動選中article_

關於sprintf,好不容易從網上找到了文章也給大家發一下吧

這個程式碼算原創有些勉強,不管怎樣粘過去,可以用在win下除錯的,我看過這個後,儘管仍然有很多迷惑,不過覺得比以前更直觀了,有了那麼一點點感覺。 #include <stdio.h> typedef char *va_list; // 此處程式碼看了兩種

關於套接字(sockets)入門的文章

套接字程式設計(sockets 譯文) 作者:Kameswari Chebrolu (印度理工學院坎普爾分校電子工程系) 卡門斯瓦力 車布羅 背景 多路解編 ●轉變“主機到主機的資料包傳輸服務”到“程式到程式的資料交流通道” 位元組次序 ●兩類“位