如圖所示,要實現這一的需求,一般人的布局方式就是左邊一button,右邊一button,中間一個EditText,為了輸入框的響應觸摸范圍更大往往不會把寬度設置為wrap_content,要么設置成match_parent/fill_parent要么給定個minWidth+wrap_content。
無論如何布局,gravity或layout_gravity都應是center才能達到需求所示。然而問題來了,如果gravity設置為了center,很不巧的是大部分手機(筆者某為竟然會自動糾正光標與hint的相對位置)實際運行效果是光標會位於hint的中間,要知道gravity會影響到光標所在位置,gravity為Left光標就在最左邊,graity為right光標就在Hint的最右邊,當然gravity為Center光標自然在hint的中間。
借圖一張(來自萬能的StackOverFlow,可惜萬能的SOF也沒給出答案)
遂冥思苦想各種彌救方法,主要有3個方案兩個角度來解決。完美的角度是把光標位置想法設法調正,退而求其次的方法是顯示hint(即輸入框沒有text)的時候隱藏光標。方案觸發點有兩個,一個是第一次沒有任何text但設置了hint此時,入口應為onFocusChange方法;另一個是動態輸入過程中清除了text,這個入口在onTextChange。
我總結出來有三個對策如下。
下策:當需要顯示hint的時候把hint設置為空字符串,不需要顯示hint的時候再把hint還原成需要設置的字符串。這種方法帶來的效果就是,界面一打開能看見hint,當你一點擊輸入框開始輸入就沒有hint了,雖然此時光標可見,但還是有瑕疵,並且在onFocusChange方法里面設置hint會造成要點兩次才會彈起輸入法(具體原因尚未深究)。
中策:當需要顯示hint的時候隱藏光標,一旦用戶開始輸入顯示光標。這種效果類似第一種,一打開界面能看見hint,但看不到光標,你要開始輸入才能看見。這也是有瑕疵的,當用戶點了輸入框(獲得用戶焦點)沒有光標用戶就會很郁悶不知道可不可以輸入,缺乏光標的引導作用。
上策:那上策就是調整位置咯,其實也不是說能調整光標的位置,而是逆向思維把輸入框的位置改變來適用光標所需要擺在的位置。這種方案實現起來有點復雜,改動量大。首先你EditTextd的寬度不能指定,minWidth不能由輸入框來設置而要在它的parent容器設置最小寬度,所以它的width最好是wrap_content,並且設置一定的padding來保留一定用戶觸摸響應區域。然后EditText的Gravity還是Center,需要調整的就是它的LayoutGravity了,當用戶有輸入毫無疑問需要居中,當沒有輸入需要顯示Hint時,那就要設置成Left了,然后計算出需要設置marginLeft距離。這個距離就是EditText(父容器的寬度-hint的寬度)/2,當然要獲取LayoutWdth需要一定的技巧,獲取hint的寬度更需要一點技巧。這樣就能讓光標位於hint的前面了,曲線救國吧。
干貨來了。
android要獲取寬高經常能拿到0這個值,這個一般有經驗的都會在onWindowsFocus里去拿到,然后量字符串的像素,就需要你要用你顯示hint的畫筆去測量字符串,因為需要知道字體屬性,比如字體、大小、粗細等。
直接上代碼咯:
@Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (mSpaceWidth <= 0) mSpaceWidth = getWidth() - left.getWidth() - right.getWidth(); } @Override public void onFocusChange(View v, boolean hasFocus) { adjustCursorPosition(etInput.getText()); } @Override public void afterTextChanged(Editable s) { adjustCursorPosition(etInput.getText()); } private void adjustCursorPosition(CharSequence text){ if (!TextUtils.isEmpty(etInput.getHint())){ adjustGravityForCursor(text);//adjustCursorVisible(text);//adjustHintContent(hasFocus(),text); } } private void adjustGravityForCursor(CharSequence text) { LayoutParams lp = (LayoutParams) etInput.getLayoutParams(); if (mSpaceWidth <= 0) mSpaceWidth = lp.width - left.getWidth() - right.getWidth(); if (!TextUtils.isEmpty(text)) { etInput.setGravity(Gravity.CENTER); lp.leftMargin = 0; } else { etInput.setGravity(Gravity.LEFT); lp.leftMargin = (mSpaceWidth - measureText(etInput,mHint)) / 2; } etInput.setLayoutParams(lp); } public int measureText(TextView textView, String text) { TextPaint paint = textView.getPaint(); return (int) paint.measureText(text); } private void adjustCursorVisible(CharSequence text){ etInput.setCursorVisible(!TextUtils.isEmpty(text)); } private void adjustHintContent(boolean hasFocus, CharSequence text){ if (TextUtils.isEmpty(text)) { etInput.setHint(hasFocus ? "" : mHint); } }