最近在項目中有使用到搜索框的地方,由於其樣式要求與iOS的UISearchBar的風格一致。默認情況下,搜索圖標和文字是居中的,在獲取焦點的時候,圖標和文字左移。但是在Android是並沒有這樣的控件(可能見識少,並不知道有)。通常情況下我們使用組合控件,使用ReleativeLayout或者FrameLayout來實現。此篇並不是使用上述方法實現,其核心是繼承系統EditText,重寫onDraw方法,來改變默認的左上右下的drawable,實現平移到中間位置。這里暫時只實現了drawableLeft的情況,后續將對其進行更新。先來看看實現效果圖:

直接來看代碼實現
package com.jinlin.custom.iconcenterview; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends BaseActivity{ private EditText et_search; private IconCenterEditText icet_search; @Override public void iniView() { setContentView(R.layout.activity_main); et_search = (EditText) findViewById(R.id.et_search); icet_search = (IconCenterEditText) findViewById(R.id.icet_search); // 實現TextWatcher監聽即可 icet_search.setOnSearchClickListener(new IconCenterEditText.OnSearchClickListener() { @Override public void onSearchClick(View view) { Toast.makeText(MainActivity.this, "i'm going to seach", Toast.LENGTH_SHORT).show(); } }); } }
這是主Activity的代碼,其繼承自BaseActivity基類,BaseActivity的實現詳細見上篇博文Android點擊空白區域,隱藏輸入法軟鍵盤只是在isShouldHideKeyboard(View v, MotionEvent event)方法內部增加一行v.clearFocus();代碼進行去除焦點處理,其他均一致。
private boolean isShouldHideKeyboard(View v, MotionEvent event) { if (v != null && (v instanceof EditText)) { int[] l = {0, 0}; v.getLocationInWindow(l); int left = l[0], top = l[1], bottom = top + v.getHeight(), right = left + v.getWidth(); if (event.getX() > left && event.getX() < right && event.getY() > top && event.getY() < bottom) { // 點擊EditText的事件,忽略它。 return false; } else { v.clearFocus(); return true; } } // 如果焦點不是EditText則忽略,這個發生在視圖剛繪制完,第一個焦點不在EditText上,和用戶用軌跡球選擇其他的焦點 return false; }
接下來是自定義View的代碼實現
IconCenterEditText.java
package com.jinlin.custom.iconcenterview; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; /** * Created by J!nl!n on 2015/1/26. */ public class IconCenterEditText extends EditText implements View.OnFocusChangeListener, View.OnKeyListener { private static final String TAG = IconCenterEditText.class.getSimpleName(); /** * 是否是默認圖標再左邊的樣式 */ private boolean isLeft = false; /** * 是否點擊軟鍵盤搜索 */ private boolean pressSearch = false; /** * 軟鍵盤搜索鍵監聽 */ private OnSearchClickListener listener; public void setOnSearchClickListener(OnSearchClickListener listener) { this.listener = listener; } public IconCenterEditText(Context context) { this(context, null); init(); } public IconCenterEditText(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.editTextStyle); init(); } public IconCenterEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setOnFocusChangeListener(this); setOnKeyListener(this); } @Override protected void onDraw(Canvas canvas) { if (isLeft) { // 如果是默認樣式,則直接繪制 super.onDraw(canvas); } else { // 如果不是默認樣式,需要將圖標繪制在中間 Drawable[] drawables = getCompoundDrawables(); if (drawables != null) { Drawable drawableLeft = drawables[0]; if (drawableLeft != null) { float textWidth = getPaint().measureText(getHint().toString()); int drawablePadding = getCompoundDrawablePadding(); int drawableWidth = drawableLeft.getIntrinsicWidth(); float bodyWidth = textWidth + drawableWidth + drawablePadding; canvas.translate((getWidth() - bodyWidth - getPaddingLeft() - getPaddingRight()) / 2, 0); } } super.onDraw(canvas); } } @Override public void onFocusChange(View v, boolean hasFocus) { Log.d(TAG, "onFocusChange execute"); // 恢復EditText默認的樣式 if (!pressSearch && TextUtils.isEmpty(getText().toString())) { isLeft = hasFocus; } } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { pressSearch = (keyCode == KeyEvent.KEYCODE_ENTER); if (pressSearch && listener != null) { /*隱藏軟鍵盤*/ InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); if (imm.isActive()) { imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), 0); } listener.onSearchClick(v); } return false; } public interface OnSearchClickListener { void onSearchClick(View view); } }
此View重寫onDraw(Canvas canvas)方法,並實現OnFocusChangeListener, OnKeyListener監聽接口,在onFocusChange(View v, boolean hasFocus)方法判斷是否需要恢復樣式,然后在onDraw(Canvas canvas)進行重繪,實現焦點失去和獲取時,平移圖標和文字。同時還會判斷軟鍵盤搜索鍵的操作進行處理。其核心代碼也就是一下這一小段:
Drawable[] drawables = getCompoundDrawables(); if (drawables != null) { Drawable drawableLeft = drawables[0]; if (drawableLeft != null) { float textWidth = getPaint().measureText(getHint().toString()); int drawablePadding = getCompoundDrawablePadding(); int drawableWidth = drawableLeft.getIntrinsicWidth(); float bodyWidth = textWidth + drawableWidth + drawablePadding; canvas.translate((getWidth() - bodyWidth - getPaddingLeft() - getPaddingRight()) / 2, 0); } }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:focusableInTouchMode="true" android:orientation="vertical" android:padding="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView style="@style/StyleTextView" android:text="默認樣式" /> <EditText android:id="@+id/et_search" style="@style/StyleEditText" /> <TextView style="@style/StyleTextView" android:text="居中樣式" /> <com.jinlin.custom.iconcenterview.IconCenterEditText android:id="@+id/icet_search" style="@style/StyleEditText" /> </LinearLayout>
bg_search_bar.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> <stroke android:width="1px" android:color="@android:color/darker_gray" /> <corners android:radius="3dp" /> </shape>
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
<style name="StyleEditText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/bg_search_bar</item>
<item name="android:drawablePadding">5dp</item>
<item name="android:drawableStart">@mipmap/icon_search</item>
<item name="android:gravity">center_vertical</item>
<item name="android:imeOptions">actionSearch</item>
<item name="android:padding">5dp</item>
<item name="android:singleLine">true</item>
<item name="android:textColorHint">@color/gray_white</item>
<item name="android:textSize">16sp</item>
<item name="android:hint">搜索</item>
</style>
<style name="StyleTextView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">40dp</item>
<item name="android:gravity">center</item>
<item name="android:textSize">20sp</item>
</style>
</resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="gray_white">#ffcccccc</color> </resources>
