Android文本,軟鍵盤全解《初級》

Android文本,軟鍵盤全解《初級》

前言

已經有一個多月沒有寫文章了,當然,我沒失蹤,我還活著!因為換了新的工作環境,所以在接手項目的時候花了點時間……不為自己做過多借口,今後持續更新好內容(還是希望自己能周更)!

這篇文章最初是記錄一個全屏模式下輸入框被軟鍵盤覆蓋的問題,要求背景不動,輸入框上移!碰巧之後項目發版,有一點時間,就想著能不能將Android文本使用做一個總結!結合之前自己做的一些筆記,這篇文章就順利產出了!

其實換工作之後,我更希望能產出高質量的文章,所以我對於這篇文章的期待其實蠻高的,希望這篇文章能幫助所有開發者解決在Android開發過程中遇到的文本問題。當然,現在文章記錄的是自己遇到的一些問題(不是很全面),希望各位在Android開發中遇到各種關於文本類的問題可以給我留言,我們一起來討論,研究對應的解決方案,完善這篇文章及項目!

目錄

Android文本,軟鍵盤全解《初級》

項目效果

文本:

Android文本,軟鍵盤全解《初級》

Android文本,軟鍵盤全解《初級》

Android文本,軟鍵盤全解《初級》

軟鍵盤:

Android文本,軟鍵盤全解《初級》

Android文本,軟鍵盤全解《初級》

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的所有屬性,裡面很多屬性大多數情況下我們都使用不到,可以稍微瞭解下,可以直接跳過屬性列表!

圖文混排的三種實現方式

1. drawableTop,DrawableBottom,DrawableLeft,drawableRight

 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中去textView通過Html實現圖文混排 點擊這一段"));

帶圖片的html的設置:

String g = "" +"" + "" +"" +
"\t

Android性能優化之APK瘦身詳解(瘦身73%)

" +"\t

公司項目在不斷的改版迭代中,代碼在不斷的累加,終於apk包不負重負了,已經到了八十多M了。可能要換種方式表達,到目前為止沒有正真的往外推過,一直在內部執行7天討論需求,5天代碼實現的階段。你在寫上個版本的內容,好了,下個版本的更新內容已經定稿了。基於這種快速開發的現狀,我們app優化前已經有87.1M了,包大了,運營說這樣轉化不高,只能好好搞一下咯。優化過後包大小為23.1M(優化了73%,不要說我標題黨)。好了好了,我要闡述我的apk超級無敵魔鬼瘦身之心得了。

" +"" +"\t" + "" + "" +"";
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的基本屬性

  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屬性來修改下劃線顏色,此方法會全局修改
@color/colorWhite80
//2. 通過修改EditText的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

Android文本,軟鍵盤全解《初級》

代碼實現

//思路參考於: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的高度
Android文本,軟鍵盤全解《初級》

代碼

  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 (https://github.com/aserbao/AserbaosAndroid)

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

總結

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

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

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

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

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


分享到:


相關文章: