自定義EditText實(shí)現(xiàn)右側(cè)圖標(biāo)
自定義MyEditText繼承EditText
package com.pump.yth.mywidget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
/**
* Created by yth on 2016/6/16.
* 重寫EditText加入對右側(cè)圖標(biāo)的點(diǎn)擊事件
*/
public class MyEditText extends EditText {
private onDrawableRightListener mRightListener;
final int DRAWABLE_RIGHT = 2;
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 綁定監(jiān)聽事件
*
* @param listener onDrawableRightListener
*/
public void setDrawableRightListener(onDrawableRightListener listener) {
this.mRightListener = listener;
}
/**
* 監(jiān)聽回調(diào)接口
*/
public interface onDrawableRightListener {
public void onDrawableRightClick(View view);
}
//判斷點(diǎn)擊位置是否是右側(cè)圖標(biāo),如果是執(zhí)行相應(yīng)的回調(diào)函數(shù)。
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mRightListener != null) {
Drawable drawableRight = getCompoundDrawables()[DRAWABLE_RIGHT];
if (drawableRight != null && event.getRawX() >= (getRight() - drawableRight.getBounds().width())) {
mRightListener.onDrawableRightClick(this);
}
}
break;
}
return super.onTouchEvent(event);
}
}
使用:
//右側(cè)圖標(biāo)點(diǎn)擊事件
mPasswordView.setDrawableRightListener(new MyEditText.onDrawableRightListener() {
@Override
public void onDrawableRightClick(View view) {
//密碼可見狀態(tài)取反
IS_PASSWORD_SHOW = !IS_PASSWORD_SHOW;
Drawable drawableright;
if (IS_PASSWORD_SHOW) {
mPasswordView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
drawableright = getResources().getDrawable(R.drawable.ic_password_hidden);
} else {
mPasswordView.setTransformationMethod(PasswordTransformationMethod.getInstance());
drawableright = getResources().getDrawable(R.drawable.ic_password_show);
}
mPasswordView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawableright, null);
}
});
注意:
用到的一些知識點(diǎn)
Android MotionEvent事件
Android View坐標(biāo)
Android MotionEvent事件響應(yīng)機(jī)制
事件主要包括點(diǎn)擊、長按、拖曳、滑動等操作,所有的事件都由如下三個部分作為基礎(chǔ)構(gòu)成:按下(action_down),移動(action_move),抬起(action_up)。
響應(yīng)歸根結(jié)底都是基于View以及ViewGroup的,這兩者中響應(yīng)的方法分別有:
在View.java中
publi boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
在ViewGroup.java中
public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)
public boolean onInterceptTouchEvent(MotionEvent event)
MotionEvent對象的理解:
當(dāng)用戶觸摸屏幕時將創(chuàng)建一個MotionEvent對象。MotionEvent包含關(guān)于發(fā)生觸摸的位置和時間等細(xì)節(jié)信息。MotionEvent對象 被傳遞到程序中合適的 方法比如View對象的onTouchEvent()方法中。在這些方法中我們可以分析MotionEvent對象,以決定要執(zhí)行的操作。
MotionEvent對象是與用戶觸摸相關(guān)的時間序列,該序列從用戶首次觸摸屏幕開始,經(jīng)歷手指在屏幕表面的任何移動,直到手指離開屏幕時結(jié)束。手指的初次觸摸(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和抬起(ACTION_UP)都會創(chuàng)建MotionEvent對象。所以每次觸摸時候這三個操作是肯定發(fā)生的,而在移動過程中會產(chǎn)生大量事件,每個事件都會產(chǎn)生對應(yīng)的MotionEvent對象記錄發(fā)生的操作,觸摸的位置,使用的多大壓力,觸摸的面積,合適發(fā)生,以及最初的ACTION_DOWN和時發(fā)生等相關(guān)的信息。
//----------------------------
dispatchTouchEvent此函數(shù)負(fù)責(zé)事件的分發(fā),當(dāng)觸摸一個View控件,首先會調(diào)用這個函數(shù)就行,在這個函數(shù)體里決定將事件分發(fā)給誰來處理。它擁有boolean類型的返回值,當(dāng)返回為true時,順序下發(fā)會中斷。
onTouchEvent 此函數(shù)負(fù)責(zé)執(zhí)行事件的處理,負(fù)責(zé)處理事件
onInterceptTouchEvent主要來決定當(dāng)前控件是否需要攔截傳遞給子控件,如果返回True表示該控件攔截,并交由自己父類的dispatchTouchEvent處理消費(fèi),如果返回false表示不攔截,允許傳遞給子控件處理。
當(dāng)Acitivty接收到Touch事件時,將遍歷子View進(jìn)行Down事件的分發(fā)。ViewGroup的遍歷可以看成是遞歸的。分發(fā)的目的是為了找到真正要處理本次完整觸摸事件的View,這個View會在onTouchuEvent結(jié)果返回true。
當(dāng)某個子View返回true時,會中止Down事件的分發(fā),同時在ViewGroup中記錄該子View。接下去的Move和Up事件將由該子View直接進(jìn)行處理。
當(dāng)ViewGroup中所有子View都不捕獲Down事件時,將觸發(fā)ViewGroup自身的onTouch事件。觸發(fā)的方式是調(diào)用super.dispatchTouchEvent函數(shù),即父類View的dispatchTouchEvent方法。在所有子View都不處理的情況下,觸發(fā)Acitivity的onTouchEvent方法。
onInterceptTouchEvent有兩個作用:1.攔截Down事件的分發(fā)。2.中止Up和Move事件向目標(biāo)View傳遞,使得目標(biāo)View所在的ViewGroup捕獲Up和Move事件。
//---------------------------------------------------------------------------
整個View的事件轉(zhuǎn)發(fā)流程是:
View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent
思路:返回ture事件被消耗,后面的不執(zhí)行了。
View.dispatchEvent->View.setOnTouchListener(onTouch)->onTouchEvent->onClick。當(dāng)onTouch返回false時,onTouchEvent才會執(zhí)行。當(dāng)onTouchEvent顯式調(diào)用onClick時(一個完整的觸發(fā),down,up),onClick才會執(zhí)行。
在dispatchTouchEvent中會進(jìn)行OnTouchListener的判斷,如果OnTouchListener不為null且返回true,則表示事件被消費(fèi),onTouchEvent不會被執(zhí)行;否則執(zhí)行onTouchEvent。

.
參考:
http://www.cnblogs.com/linjzong/p/4191891.html
http://www.2cto.com/kf/201406/308037.html
http://blog.csdn.net/lmj623565791/article/details/38960443
http://www.android100.org/html/201502/26/123262.html 做實(shí)驗(yàn)驗(yàn)證一樣。
getLeft()和getTop()可以得到一個View的位置。這兩個方法返回的是相對于其父元素的位置
getRight() =getLeft() + getWidth()
getBottom()= getTop() + getHeight()
//可以在上、下、左、右設(shè)置圖標(biāo),如果不想在某個地方顯示,則設(shè)置為null。圖標(biāo)的寬高將會設(shè)置為固有寬高,既自動通過getIntrinsicWidth和getIntrinsicHeight獲取
setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom)
//可以在上、下、左、右設(shè)置圖標(biāo),如果不想在某個地方顯示,則設(shè)置為null。但是Drawable必須已經(jīng)setBounds(Rect)
setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom)
//這個方法要先給Drawable設(shè)置
setBounds(x,y,width,height);
//設(shè)置EdiText的password的隱藏與顯示
setTransformationMethod