今天來聊聊TextWatcher~
TextWatcher是google在android.text之下提供的一個方法
https://developer.android.com/reference/android/text/TextWatcher
簡單來說他的功能是即時監控EditText輸入狀況的一個方法
像是想要限制只能輸入到小數點以下幾位、或者限制輸入範圍並即時反饋
都可以在這個方法中實踐(´・з・)
今天的範例將利用此功能特性,即時計算出十進位轉為各種進位的應用
以下為範例
以及GitHub
https://github.com/thumbb13555/EditTextTextWatcherExample
OK,開始
本次功能描述:
1.輸入10進制數值時即時轉為其他進制並顯示
2.輸入範圍僅-500~+500
3.輸入開頭不可為0
4.超過超入範圍即立即修正為最大值或最小值
在開始之前要先了解這項功能以及所附帶的三個複寫
首先先畫好layout
在Layout設計上,EditText中有設置幾個EditText常用的方法
android:digits="-1234567890"
表示限制輸入只能為以上所輸入的這些
android:inputType="numberDecimal|numberSigned"
表示輸入限制為數字以及可輸入小數點
至於其他三個EditText我則是在xml中把他設置為不可點擊的狀態
方法則是
android:focusable="false"
另外,inputType也可以在程式中設置
edInput.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL|InputType.TYPE.NUMBER_FLAG_SIGNED);
OK回到程式
首先要先來處理轉進制的問題
老實講我覺得Java中將別的進制轉過來10進制麻煩
但是要把10進制轉為其他進制卻都是一行可以搞定的事情(´・д・`)
轉換時只要這樣(紅字)就可以了
int getVal = Integer.parseInt(String.valueOf(100));
edBinary.setText(Integer.toBinaryString(getVal));//轉二進
edOctal.setText(Integer.toOctalString(getVal));//轉八進
edHex.setText(Integer.toHexString(getVal));//轉十六進
一如既往地先在onCreate內抓好元件後,就可以來做今天的重點了
先po一下onCreate內準備工作
public class MainActivity extends AppCompatActivity {
EditText edInput,edBinary,edOctal,edHex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edInput = findViewById(R.id.edInput);
edBinary= findViewById(R.id.edBinary);
edOctal = findViewById(R.id.edOctal);
edHex = findViewById(R.id.edHex);
}
}
然後一樣在onCreate內,打上這行
edInput.addTextChangedListener(new TextWatcher() {...}
按下TextWatcher後,就會跳出我們要的東西囉
跳出來的東西如下
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
總共會跳出三個回調
分別是
beforeTextChanged
onTextChanged
afterTextChanged
如果單從字面上的意思解讀,就是
文字變更之前
文字變更中
文字變更後
好我知道還是聽得霧颯颯..(・ω・`)………..
於是我們來做一個實驗
我在所有方法中都放一個Log來觀察他值變化的狀況
首先當我們在沒有輸入時輸入"4"
可以看見輸入前的s紀錄了"",因為原本是還沒輸入的
紀錄中的s=4, 以及修改會結果為4
再來輸入一個“2”
現在畫面中顯示是“42”了
然後再一個”3“
現在是"423"
現在我們刪掉最後的"3"
現在是"42"
最後我們刪掉"42"中的"4"
現在畫面是"2"了
分析過程就不再贅述,直接講結論
在beforeTextChanged中
s代表是修改(輸入)以前的數值
start代表是發生修改的位置
count是發生修改的時的文字長度,新增輸入時回傳0
after則是修改後的字串長度,刪除字串時回傳0
在onTextChanged中
s代表變更後的字串
start代表被變更的序號
before代表被改變的字串長度,新增時回傳0
count為添加字符的長度,如果是刪除的話回傳0
最後afterTextChanged就單純很多
s就是修改後的文字
最後我要分享一個踩過的坑
而且搞笑的是這是在官網中所寫過的注意事項..
蛤?你問我什麼意思(╭ರ_⊙)
一言以敝之就是
因為這兩個複寫方法會即時偵測EditText內的數值變更
因此如果這時候你在這個複寫內去修改本來的EditText的值的話
那你就會陷入無窮迴圈,導致當機。
雖然我不是照著英文翻給你聽,但是就是這麼一回事
於是我來採坑給你看你就知道我在說什麼啦(*-ω-)
首先我來在beforeTexttChanged內加入edInput.setText();
然後看著LogCat執行..
喔淦(✿・∀・)┌∩┐
醬子有沒有理解了一咪咪呢XDDDDDDD
好的,坑先踩到這邊,我們繼續
再來的工作是要先設置即時顯示的值
於是我在onTextChanged寫
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int getVal = Integer.parseInt(String.valueOf(s));
edBinary.setText(Integer.toBinaryString(getVal));
edOctal.setText(Integer.toOctalString(getVal));
edHex.setText(Integer.toHexString(getVal));
}
@Override
public void afterTextChanged(Editable s) {
}
});
好的來測試吧XD
看起來是沒問題...喔淦 凸(✿・∀・)凸
閃退惹 (´・д・`)
來看一下LogCat
恩...數字格式錯誤因為輸入值為""
好ㄅ,只好來解決問題了
我的方法是索性加入try-catch,直接給他去錯這樣
於是我的程式變成這樣
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
int getVal = Integer.parseInt(String.valueOf(s));
edBinary.setText(Integer.toBinaryString(getVal));
edOctal.setText(Integer.toOctalString(getVal));
edHex.setText(Integer.toHexString(getVal));
}catch (Exception e){
edBinary.setText("");
edOctal.setText("");
edHex.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
醬子就完成囉(`・ω・´)b
接下來我們要來完成功能2,限制輸入範圍
上面有提到我們不能夠在beforeTextChanged以及onTextChanged內做任何edInput的更動
那怎模辦?所以只能找剩下的啦~~
沒錯~就是寫在afterTextChanged內
٩(•౪•٩)三
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
int getVal = Integer.parseInt(String.valueOf(s));
edBinary.setText(Integer.toBinaryString(getVal));
edOctal.setText(Integer.toOctalString(getVal));
edHex.setText(Integer.toHexString(getVal));
}catch (Exception e){
edBinary.setText("");
edOctal.setText("");
edHex.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
try {
int getInput = Integer.parseInt(String.valueOf(s));
if (getInput>500){
edInput.setText("500");
edInput.setSelection(s.length());
}else if (getInput<-500){
edInput.setText("-500");
edInput.setSelection(s.length());
}
}catch (Exception e){
edBinary.setText("");
edOctal.setText("");
edHex.setText("");
}
}
});
至於第四項要求只要在條件是內設定setText就可以囉!
至於最後的那個edInput.setSelection(s.length());則是控制光標的位置
好的,最後來完成第三項
有時候齁...不管你程式再怎麼用心就是總有那麼幾個人能夠超越86
像這樣
欸欸工程師~你可以限制讓客人不要亂輸入嗎˚▱˚
...XXX好好的輸入是不會膩!一定要這麼智障嗎?
好啦就結論而言我並沒有解決掉畫面中那種輸入
但是我現在講的邏輯延伸是可以
第三項要求:數字前不可有零
方法很簡單,簡單來說就是偵測並取代
於是我的程式長這樣
edInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("MyTAG", "beforeTextChanged: s= "+s+", start= "
+start+", count= "+count+", after= "+after);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d("MyTAG", "onTextChanged: s= "+s+", start= "
+start+", before= "+before+", count= "+count);
try {
int getVal = Integer.parseInt(String.valueOf(s));
edBinary.setText(Integer.toBinaryString(getVal));
edOctal.setText(Integer.toOctalString(getVal));
edHex.setText(Integer.toHexString(getVal));
}catch (Exception e){
edBinary.setText("");
edOctal.setText("");
edHex.setText("");
}
}
@Override
public void afterTextChanged(Editable s) {
Log.d("MyTAG", "afterTextChanged: s= "+s);
Log.d("MyTAG", "=========分隔線=========");
try {
int getInput = Integer.parseInt(String.valueOf(s));
if (getInput>500){
edInput.setText("500");
edInput.setSelection(s.length());
}else if (getInput<-500){
edInput.setText("-500");
edInput.setSelection(s.length());
}
if (s.toString().length() > 1 && s.toString().startsWith("0")) {
s.replace(0,1,"");
}
}catch (Exception e){
edBinary.setText("");
edOctal.setText("");
edHex.setText("");
}
}
});
條件:如果輸入長度>0而且開頭第一個字為"0"的話
就將第零位替換掉變成""
就這樣而已~沒了XD
很簡單吧哈哈
結論:
TextWatcher雖然不是個很常用的元件,但是卻是在專業APP中的常用元件之一
一個好的APP操作體驗佳是很重要滴...我是這麼認為啦
這個功能再結合進制轉換以及加減乘除
就可以完成像計算機一樣的APP了!
那今天的介紹到這!掰逼~
留言列表