1. 程式人生 > >自定義EditText實現類iOS風格搜尋框

自定義EditText實現類iOS風格搜尋框

最近在專案中有使用到搜尋框的地方,由於其樣式要求與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>