Android UI設(shè)計(jì)系列之自定義EditText實(shí)現(xiàn)帶清除功能的輸入框(3)
最近公司的產(chǎn)品在陸續(xù)做升級(jí),上級(jí)領(lǐng)導(dǎo)給的任務(wù)是優(yōu)化代碼結(jié)構(gòu)以及項(xiàng)目架構(gòu),力爭(zhēng)把項(xiàng)目寫(xiě)的精巧簡(jiǎn)練,于是我們滿工程找冗余...
我們都知道每一個(gè)項(xiàng)目基本上都是有登陸頁(yè)的,在登陸頁(yè)中肯定是少不了輸入框了,當(dāng)我們?cè)谳斎肟蛑休斎霐?shù)據(jù)后如果輸入的內(nèi)容不正確或者是錯(cuò)誤的或者是想重新輸入,如果嗯鍵盤(pán)上的刪除鍵就得一個(gè)一個(gè)的去刪除,這時(shí)候我們或許就想要是能有一個(gè)標(biāo)記當(dāng)點(diǎn)擊了這個(gè)標(biāo)記能把我們剛剛輸入的內(nèi)容清空就好了。這樣可以極大的提升用戶體驗(yàn),就拿QQ的登陸來(lái)說(shuō)吧,效果如下:

當(dāng)點(diǎn)擊密碼框右側(cè)的小×圖標(biāo)時(shí)輸入的內(nèi)容就都清空了,真的很方便,我之前在項(xiàng)目中也自定義過(guò)這種效果的輸入框并且在項(xiàng)目中一直使用它,在此期間并沒(méi)有發(fā)現(xiàn)什么Bug,之前的自定義結(jié)構(gòu)如下:

實(shí)現(xiàn)方式是使用一個(gè)RelativeLayout,它包含了三個(gè)控件,兩邊是ImageView控件,中間是EditText控件,當(dāng)點(diǎn)擊右側(cè)清除按鈕后就可以清除輸入框的內(nèi)容了,但是最近在做產(chǎn)品優(yōu)化的時(shí)候感覺(jué)之前寫(xiě)的這個(gè)自定義控件在代碼量上來(lái)說(shuō)有點(diǎn)浪費(fèi),明明Android的EditText有drawableLeft和drawableRight屬性,為什么不去直接使用呢?于是用筆在草稿紙上畫(huà)了畫(huà),花點(diǎn)時(shí)間又重新寫(xiě)了一個(gè)具有同樣效果的輸入框,并且在代碼量上來(lái)說(shuō)簡(jiǎn)化了不少。
好了,還是老規(guī)矩,先來(lái)看看項(xiàng)目結(jié)構(gòu)吧:

工程中ClearEditText就是我又從新定義的帶清除功能的輸入框,主要是繼承了EditText為了利用它的drawableLeft和drawableRight屬性,那么趕緊看看它的實(shí)現(xiàn)吧
public class ClearEditText extends EditText implements TextWatcher,
OnFocusChangeListener {
/**
* 左右兩側(cè)圖片資源
*/
private Drawable left, right;
/**
* 是否獲取焦點(diǎn),默認(rèn)沒(méi)有焦點(diǎn)
*/
private boolean hasFocus = false;
/**
* 手指抬起時(shí)的X坐標(biāo)
*/
private int xUp = 0;
public ClearEditText(Context context) {
this(context, null);
}
public ClearEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.editTextStyle);
}
public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initWedgits();
}
/**
* 初始化各組件
* @param attrs
* 屬性集
*/
private void initWedgits() {
try {
// 獲取drawableLeft圖片,如果在布局文件中沒(méi)有定義drawableLeft屬性,則此值為空
left = getCompoundDrawables()[0];
// 獲取drawableRight圖片,如果在布局文件中沒(méi)有定義drawableRight屬性,則此值為空
right = getCompoundDrawables()[2];
initDatas();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化數(shù)據(jù)
*/
private void initDatas() {
try {
// 第一次顯示,隱藏刪除圖標(biāo)
setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
addListeners();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 添加事件監(jiān)聽(tīng)
*/
private void addListeners() {
try {
setOnFocusChangeListener(this);
addTextChangedListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int after) {
if (hasFocus) {
if (TextUtils.isEmpty(s)) {
// 如果為空,則不顯示刪除圖標(biāo)
setCompoundDrawablesWithIntrinsicBounds(left, null, null, null);
} else {
// 如果非空,則要顯示刪除圖標(biāo)
if (null == right) {
right = getCompoundDrawables()[2];
}
setCompoundDrawablesWithIntrinsicBounds(left, null, right, null);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// 獲取點(diǎn)擊時(shí)手指抬起的X坐標(biāo)
xUp = (int) event.getX();
// 當(dāng)點(diǎn)擊的坐標(biāo)到當(dāng)前輸入框右側(cè)的距離小于等于getCompoundPaddingRight()的距離時(shí),則認(rèn)為是點(diǎn)擊了刪除圖標(biāo)
// getCompoundPaddingRight()的說(shuō)明:Returns the right padding of the view, plus space for the right Drawable if any.
if ((getWidth() - xUp) <= getCompoundPaddingRight()) {
if (!TextUtils.isEmpty(getText().toString())) {
setText("");
}
}
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
return super.onTouchEvent(event);
}
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
try {
this.hasFocus = hasFocus;
} catch (Exception e) {
e.printStackTrace();
}
}
}
解釋一下ClearEditText的執(zhí)行順序,它首先繼承了EditText也就是說(shuō)具有了EditText的所有功能,然后又實(shí)現(xiàn)了TextWatcher和OnFocusChangeListener接口,其中接口OnFocusChangeListener是用來(lái)監(jiān)聽(tīng)當(dāng)前輸入框是否獲取到焦點(diǎn)的,我們把當(dāng)前輸入框獲取到的焦點(diǎn)的狀態(tài)值賦給hasFocus成員變量,如果獲取到了焦點(diǎn)則hasFocus的值為true,當(dāng)在輸入框中輸入內(nèi)容的時(shí)候會(huì)觸發(fā)TextWatcher監(jiān)聽(tīng)器,就會(huì)順序執(zhí)行beforeTextChanged,onTextChanged和afterTextChanged方法,而我們僅僅需要在onTextChanged方法中對(duì)輸入框的值進(jìn)行判斷就行了,如果輸入框框的值非空就顯示清空按鈕小圖標(biāo)否則不顯示,設(shè)置圖標(biāo)隱藏和顯示的方法就是直接調(diào)用setCompoundDrawablesWithIntrinsicBounds方法就行了,這個(gè)方法的具體使用就不詳解了,大體就是說(shuō)按照我們給定的圖片尺寸把圖片畫(huà)到輸入框的四個(gè)方向上,如果傳入值為null就表示不繪制。
接下來(lái)就是對(duì)清空小圖標(biāo)進(jìn)行監(jiān)聽(tīng)了,我首先想到的是如果清空小圖標(biāo)是顯示的,就給他設(shè)置事件監(jiān)聽(tīng)比如onClickListener或者是onTouchListener,但是遺憾的是找了API并沒(méi)有發(fā)現(xiàn)EditText提供對(duì)drawLeft或者是drawRight的事件監(jiān)聽(tīng),又來(lái)又打算自定義一個(gè)監(jiān)聽(tīng)器但仔細(xì)想想又把代碼復(fù)雜化了,其實(shí)EditText是間接繼承View的而View中有個(gè)onTouchEvent方法,我們可以重寫(xiě)onTouchEvent方法并在它里邊根據(jù)我們手指摁下或者是抬起的坐標(biāo)進(jìn)行判斷,如果點(diǎn)擊的位置到當(dāng)前控件右側(cè)的距離小于等于當(dāng)前控件右側(cè)小圖標(biāo)的寬度加上paddingRight的值,則我們可以直接認(rèn)為是點(diǎn)擊了清除小圖標(biāo),就可以對(duì)當(dāng)前控件進(jìn)行清空操作了,幸好EditText給我們提供了一個(gè)我現(xiàn)在認(rèn)為是非常實(shí)在的方法:getCompoundPaddingRight(),文檔的解釋就是:Returns the right padding of the view, plus space for the right Drawable if any.它的值就是清空小圖標(biāo)的寬度加上paddingRight的值,呵呵,有了它就好辦多了,(*^__^*) 嘻嘻……
好了,接下來(lái)我們來(lái)看看在布局文件中怎么使用它吧(其實(shí)很簡(jiǎn)單,就是和EditText的使用方法一樣的,(*^__^*) 嘻嘻……)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ffffff"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:text="@string/hello" android:gravity="center" android:textSize="20sp" android:textColor="#000000" /> <com.llew.e.clear.view.wedgit.ClearEditText android:id="@+id/clearEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:paddingRight="8dip" android:paddingTop="5dip" android:paddingBottom="5dip" android:hint="請(qǐng)輸入QQ號(hào)碼" android:background="@drawable/pay_widget_input" android:drawableLeft="@drawable/super_qq" android:drawableRight="@drawable/clear_normal_list" /> </LinearLayout>
就是寫(xiě)完整我們自定義的包名就行了,屬性用的全是父類中的,再次感謝Java給我們提供的繼承特性,呵呵,
在運(yùn)行之前還是貼出來(lái)MainActivity代碼吧,其實(shí)真的很簡(jiǎn)單:
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
簡(jiǎn)單吧?創(chuàng)建工程的時(shí)候自動(dòng)生成的,壓根不用進(jìn)行任何操作,呵呵
好了,我們運(yùn)行一下,看看效果圖吧O(∩_∩)O~
輸入前:

輸入后:

點(diǎn)擊清除圖標(biāo)后:

呵呵,這種效果和之前自定義的一樣,并且在代碼量上來(lái)說(shuō)卻是比之前的減少了不少,高興一下
好了,今天的自定義ClearEditText就講到這里,感謝收看。
源碼下載:Android UI實(shí)現(xiàn)帶清除功能的輸入框
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 5種方法完美解決android軟鍵盤(pán)擋住輸入框方法詳解
- Android高級(jí)xml布局之輸入框EditText設(shè)計(jì)
- Android文本輸入框(EditText)輸入密碼時(shí)顯示與隱藏
- Android實(shí)現(xiàn)動(dòng)態(tài)顯示或隱藏密碼輸入框的內(nèi)容
- 解決Android軟鍵盤(pán)彈出覆蓋h5頁(yè)面輸入框問(wèn)題
- Android軟鍵盤(pán)擋住輸入框的終極解決方案
- Android仿支付寶自定義密碼輸入框及安全鍵盤(pán)(密碼鍵盤(pán))
- Android 自定義密碼輸入框?qū)崿F(xiàn)代碼
- Android實(shí)現(xiàn)常見(jiàn)的驗(yàn)證碼輸入框?qū)嵗a
- Android自定義九宮格輸入框
相關(guān)文章
Android離線Doc文檔訪問(wèn)速度慢的有效解決方法
今天小編就為大家分享一篇關(guān)于Android離線Doc文檔訪問(wèn)速度慢的有效解決方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
Android控件之ProgressBar用法實(shí)例分析
這篇文章主要介紹了Android控件之ProgressBar用法,以一個(gè)完整實(shí)例形式較為詳細(xì)的分析了ProgressBar控件操作進(jìn)度顯示的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(ESC/POS指令篇)
這篇文章主要介紹了Android 藍(lán)牙連接 ESC/POS 熱敏打印機(jī)打印實(shí)例(ESC/POS指令篇),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04
Android View事件分發(fā)和消費(fèi)源碼簡(jiǎn)單理解
這篇文章主要介紹了Android View事件分發(fā)和消費(fèi)源碼簡(jiǎn)單理解的相關(guān)資料,需要的朋友可以參考下2017-07-07
Android?Jetpack組件Lifecycle源碼解析
這篇文章主要為大家介紹了Android?Jetpack組件Lifecycle源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Ubuntu中為Android簡(jiǎn)單介紹硬件抽象層(HAL)
本文主要介紹在Android 的硬件抽象層,學(xué)習(xí)Android 硬件抽象層(HAL)對(duì)理解整個(gè)Android都是有非常大的作用,有興趣的小伙伴可以參考下2016-08-08
Android基于socket實(shí)現(xiàn)的簡(jiǎn)單C/S聊天通信功能
這篇文章主要介紹了Android基于socket實(shí)現(xiàn)的簡(jiǎn)單C/S聊天通信功能,結(jié)合實(shí)例形式分析了Android使用socket實(shí)現(xiàn)客服端與服務(wù)器端數(shù)據(jù)的發(fā)送與接收處理技巧,需要的朋友可以參考下2016-10-10

