1. 程式人生 > >Android EditText響應drawableRight等的點選事件

Android EditText響應drawableRight等的點選事件

前言

我們在輸入框EditText中,經常會新增比如刪除X,下拉箭頭等圖示,以得到更好的使用者體驗和需求,如果放在右邊,我們經常設定drawableRight屬性來實現,那麼這些圖示如何響應點選事件呢?下面簡單記錄一下!

方法

首先我們要繼承AppCompatEditText,實現一個自定義的EditText(現在一般為了相容和實現MD風格,都會繼承AppCompatEditText,而不再去繼承EditText,另外AS也會給出相應的錯誤警告提示!)

然後藉助於onTouchEvent,根據觸控位置來響應圖示的點選事件,判斷手指擡起的時候的x,y座標是否點選在drawable物件上。其中需要搞清楚這幾個引數:

event.getRawX()//相對於左邊界的絕對座標,以左上角為(0,0)
event.getX()//相對於自身的座標,以該空間的左上角為(0,0)
getLeft()//相當於margin,控制元件左邊界相對於父控制元件的距離
getPaddingLeft()//相當於padding,控制元件中元素相對於控制元件的間距
getBounds().width()//獲取元素繪製區域的寬度
drawableRight.getIntrinsicWidth()//獲取drawable的實際寬度

那麼就需要得到這個圖示,這裡通過呼叫getCompoundDrawables() 可以獲取一個長度為4的drawable陣列,存放drawableLeft,Right,Top,Bottom四個圖片資源物件:

    final int DRAWABLE_LEFT = 0;
    final int DRAWABLE_TOP = 1;
    final int DRAWABLE_RIGHT = 2;
    final int DRAWABLE_BOTTOM = 3;

可以根據圖示的位置,拿到對應的圖片Drawable。

最後,通過宣告一個介面,定義一個回撥方法,這裡就不細說了,比較常見了!

具體實現

public class DropDownEditText extends AppCompatEditText {
    final int DRAWABLE_LEFT = 0;
    final
int DRAWABLE_TOP = 1; final int DRAWABLE_RIGHT = 2; final int DRAWABLE_BOTTOM = 3; public DropDownEditText(Context context) { super(context); } public DropDownEditText(Context context, AttributeSet attrs) { super(context, attrs); } public interface OnDropArrowClickListener { void onDropArrowClick(); } private OnDropArrowClickListener onDropArrowClickListener; public void setOnDropArrowClickListener(OnDropArrowClickListener onDropArrowClickListener) { this.onDropArrowClickListener = onDropArrowClickListener; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { Drawable drawableRight = getCompoundDrawables()[DRAWABLE_RIGHT]; if (drawableRight != null) { //本次點選事件的x軸座標,如果>當前控制元件寬度-控制元件右間距-drawable實際展示大小 if (event.getX() >= (getWidth() - getPaddingRight() - drawableRight.getIntrinsicWidth())) { //設定點選EditText右側圖示EditText失去焦點, // 防止點選EditText右側圖示EditText獲得焦點,軟鍵盤彈出 setFocusableInTouchMode(false); setFocusable(false); if (onDropArrowClickListener != null) { onDropArrowClickListener.onDropArrowClick(); } } else { setFocusableInTouchMode(true); setFocusable(true); } } } return super.onTouchEvent(event); } }

示例中展示了圖示在右邊的情況,同樣的其他的位置:
右邊:

//另外一種直接的方法
//其實就是算該drawable最左邊的x座標,drawableRight.getIntrinsicWidth()==drawableRight.getBounds().width()等於圖示的寬度
event.getRawX() >= (getRight() - drawableRight.getBounds().width())

左邊:

/**getX是相對於控制元件本身的左上角的x座標,<= 控制元件左邊距+圖片物件實際的寬度.這邊的getLeft相當於margin,getPaddingLeft相當於padding*/
event.getX() <= getLeft() + drawableLeft.getIntrinsicWidth()


event.getRawX() <= (getLeft() + drawableLeft.getBounds().width())

上邊:

event.getY() <= getTop() + drawableTop.getIntrinsicHeight()

下邊:

event.getX() > getHeight() - drawableBottom.getIntrinsicWidth()

呼叫

直接得到例項,呼叫方法即可:

editText = (DropDownEditText) findViewById(R.id.xxxxx);
editText.setOnDropArrowClickListener(new DropDownEditText.OnDropArrowClickListener() {
    @Override
    public void onDropArrowClick() {
        //xxxxxxxx
    }
});

問題

setFocusableInTouchMode(false);
setFocusable(false);

這種方法,雖然可以避免彈出輸入法,但是EditText下邊的線,還是會亮一下,感覺體驗不太好,如果有知道的,可以指導一下,謝謝!