1. 程式人生 > >【Android自定義控制元件】仿IOS風格的搜尋框

【Android自定義控制元件】仿IOS風格的搜尋框

IOS很多控制元件的設計都是很值得借鑑的存在,作為移動開發的初學者,我們可以把這種模仿等同於學畫、練字時為鑄就基礎的臨摹行為。達者為師,努力學習別人的優點吧。
這裡是仿IOS搜尋框風格的自定義控制元件,引用了http://blog.csdn.net/djl461260911/article/details/46401139 這篇部落格的程式碼,加入了清除按鈕的功能。吐槽下csdn的編輯器,忽略縮排真的很影響介面效果。

1.控制元件最終效果圖:
1)控制元件未獲得焦點時如下:
這裡寫圖片描述
2)點選開始編輯時:
注意軟體盤右下角的回車鍵變成了搜尋樣式,同時搜尋圖示和hint text已經移動到編輯框最左邊
這裡寫圖片描述


3)焦點離開時:
這裡寫圖片描述
4)輸入內容,刪除按鈕在最右邊出現:
這裡寫圖片描述
5)刪除按鈕按下變色,已經按下後清除內容就不一一截圖了。

2.程式碼實現:
1)控制元件樣式檔案 style.xml

<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="editTextStyle">
        <item name="android:layout_width">match_parent</item
> <item name="android:layout_height">wrap_content</item> <item name="android:background">@drawable/search_edit_bg</item> <item name="android:drawablePadding">5dp</item> <item name="android:drawableStart">@drawable/search_icon</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:textSize">16sp</item> <item name="android:hint">搜尋</item> </style> <style name="textViewStyle"> <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>
2)控制元件顏色資原始檔colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="search_edit_gray">#ffcccccc</color>
</resources>
3)控制元件圖片資源:

edit_delete_icon.png
這裡寫圖片描述
edit_delete_pressed_icon.png
這裡寫圖片描述
search_icon.png
這裡寫圖片描述
4)控制元件程式碼 SearchEditText .java
從介面優化思想來說,自定義控制元件也要儘可能的減少佈局節點,因此使用ViewGroup來自定義控制元件應該儘量避免。

public class SearchEditText extends EditText implements OnFocusChangeListener, OnKeyListener, TextWatcher{
private static final String TAG = "SearchEditText";
/**
* 圖示是否預設在左邊
*/
private boolean isIconLeft = false;
/**
* 是否點選軟鍵盤搜尋
*/
private boolean pressSearch = false;
/**
* 軟鍵盤搜尋鍵監聽
*/
private OnSearchClickListener listener;

private Drawable[] drawables; // 控制元件的圖片資源
private Drawable drawableLeft, drawableDel; // 搜尋圖示和刪除按鈕圖示
private int eventX, eventY; // 記錄點選座標
private Rect rect; // 控制元件區域

public void setOnSearchClickListener(OnSearchClickListener listener) {
this.listener = listener;
}

public interface OnSearchClickListener {
void onSearchClick(View view);
}

public SearchEditText(Context context) {
this(context, null);
init();
}


public SearchEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.editTextStyle);
init();
}


public SearchEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init() {
setOnFocusChangeListener(this);
setOnKeyListener(this);
addTextChangedListener(this);
}


@Override
protected void onDraw(Canvas canvas) {
if (isIconLeft) { // 如果是預設樣式,直接繪製
if (length() < 1) {
drawableDel = null;
}
this.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, null, drawableDel, null);
super.onDraw(canvas);
} else { // 如果不是預設樣式,需要將圖示繪製在中間
if (drawables == null) drawables = getCompoundDrawables();
if (drawableLeft == null) drawableLeft = drawables[0];
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) {
// 被點選時,恢復預設樣式
if (!pressSearch && TextUtils.isEmpty(getText().toString())) {
isIconLeft = 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;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
// 清空edit內容
if (drawableDel != null && event.getAction() == MotionEvent.ACTION_UP) {
eventX = (int) event.getRawX();
            eventY = (int) event.getRawY();
            Log.i(TAG, "eventX = " + eventX + "; eventY = " + eventY);
            if (rect == null) rect = new Rect();
            getGlobalVisibleRect(rect);
            rect.left = rect.right - drawableDel.getIntrinsicWidth();
            if (rect.contains(eventX, eventY)) {
            setText("");
            }
}
// 刪除按鈕被按下時改變圖示樣式
if (drawableDel != null && event.getAction() == MotionEvent.ACTION_DOWN) {
eventX = (int) event.getRawX();
            eventY = (int) event.getRawY();
            Log.i(TAG, "eventX = " + eventX + "; eventY = " + eventY);
            if (rect == null) rect = new Rect();
            getGlobalVisibleRect(rect);
            rect.left = rect.right - drawableDel.getIntrinsicWidth();
            if (rect.contains(eventX, eventY))
            drawableDel = this.getResources().getDrawable(R.drawable.edit_delete_pressed_icon);
} else {
drawableDel = this.getResources().getDrawable(R.drawable.edit_delete_icon);
}
return super.onTouchEvent(event);
}


@Override
public void afterTextChanged(Editable arg0) {
if (this.length() < 1) {
drawableDel = null;
} else {
drawableDel = this.getResources().getDrawable(R.drawable.edit_delete_icon);
}
}


@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}

@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
            int arg3) {
    }
}

3.Activity演示程式碼
1)佈局檔案 activity_main.xml
初學者注意這裡自定義控制元件的包名,填寫控制元件實際所在包路徑

<RelativeLayout 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:padding="5dp"
    android:focusable="true" 
android:focusableInTouchMode="true"
    tools:context=".MainActivity" >


    <com.example.material.widget.SearchEditText
        android:id="@+id/activity_main_input_edittext"
        style="@style/editTextStyle"
        android:layout_marginTop="20dp" />

    <com.example.material.widget.SearchEditText
        android:id="@+id/activity_main_input_edittext2"
        style="@style/editTextStyle"
        android:layout_below="@+id/activity_main_input_edittext"
        android:layout_marginTop="20dp" />


</RelativeLayout>
2)Activity程式碼 MainActivity.java
public class MainActivity extends ActionBarActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}