2012-02-21 65 views
55

我有一個EditText字段,上面有一個Customer Text Watcher。在一段代碼中,我需要更改EditText中的值,我使用.setText("whatever")如何在不觸發Text Watcher的情況下更改EditText文本?

問題是,只要我做了改變afterTextChanged方法被調用,創建了一個無限循環。如何在不觸發afterTextChanged的情況下更改文本?

我需要afterTextChanged方法中的文本,所以不建議刪除TextWatcher

回答

42

您可以註銷觀察者,然後重新註冊它。

或者,您可以設置一個標誌,以便您的觀察者知道您何時自己更改了文本(因此應該忽略它)。

+0

你的提示對我來說已經足夠了。實際上,我在onResume中註冊了監聽器,但沒有在onPause()中註銷,所以它多次調用。 – Smeet 2017-06-07 12:04:13

-1

從文本更改偵聽器中設置文本時可能會發生無限循環。 如果是這種情況,最好不要從那裏設置文本。 所以你會解決循環問題,沒有理由繞過或消耗事件。

+0

我想知道爲什麼有人-1我的答案昨天,5年後,我已經回答。答案對我來說依然很合理。 – auval 2018-01-14 09:39:14

10

簡單的技巧修復... 只要你的邏輯推導出新的編輯文本值是冪等性的(它可能是,但只是說)。在您的偵聽器方法中,如果當前值不同於上次修改值時修改編輯文本。

例如,

TextWatcher tw = new TextWatcher() { 
    private String lastValue = ""; 

    @Override 
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
    } 

    @Override 
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
    } 

    @Override 
    public void afterTextChanged(Editable editable) { 

    // Return value of getNewValue() must only depend 
    // on the input and not previous state 
    String newValue = getNewValue(editText.getText().toString()); 
    if (!newValue.equals(lastValue)) { 
     lastValue = newValue; 

     editText.setText(newValue); 
    } 
    } 
}; 
-1

您應該確保您的實現文本的變化是穩定的,如果不需要改變不會更改文本。通常情況下,這將是任何已經通過觀察者的內容。

最常見的錯誤是在關聯的EditText或Editable中設置新文本,即使文本實際上並未發生更改。最重要的是,如果您對Editable進行更改而不是某個特定的View,則可以輕鬆地重新使用觀察器,並且還可以使用某些單元測試單獨進行測試,以確保它具有您想要的結果。

由於Editable是一個接口,您甚至可以使用它的虛擬實現,在測試應該穩定的內容時,如果調用其任何方法以嘗試更改其內容,則會引發RuntimeException。

0

我的變種:

public class CustomEditText extends AppCompatEditText{ 
    TextWatcher l; 

    public CustomEditText(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 
    public void setOnTextChangeListener(TextWatcher l) { 
     try { 
      removeTextChangedListener(this.l); 
     } catch (Throwable e) {} 
     addTextChangedListener(l); 
     this.l = l; 
    } 

    public void setNewText(CharSequence s) { 
     final TextWatcher l = this.l; 
     setOnTextChangeListener(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) { 

      } 
     }); 
     setText(s); 
     post(new Runnable() { 
      @Override 
      public void run() { 
       setOnTextChangeListener(l); 
      } 
     }); 
    } 


} 

組偵聽只能用setOnTextChangeListener(),並設置文本僅使用setNewText(我想重寫的setText(),但它是決賽)

0

試試這個邏輯: 我想setText(「」)沒有無限循環,這段代碼適用於我。我希望你能修改此以滿足您的需求

 final EditText text= (EditText)findViewById(R.id.text); 
     text.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) { 
      if(s.toString().isEmpty())return; 
      text.setText(""); 
      //your code 
     } 
    }); 
51

您可以檢查哪些查看當前具有焦點的用戶和程序之間的區分觸發事件。

EditText myEditText = (EditText) findViewById(R.id.myEditText); 

myEditText.addTextChangedListener(new TextWatcher() { 

    @Override 
    public void onTextChanged(CharSequence s, int start, int before, int count) { 
     if (getCurrentFocus() == myEditText) { 
      // is only executed if the EditText was directly changed by the user 
     } 
    } 

    //... 
}); 

編輯:作爲LairdPleng正確提到的,如果myEditText已經具有焦點,這並不工作,並以編程方式更改文本。因此,在致電myEditText.setText(...)之前,您應該致電myEditText.clearFocus()作爲Chack表示,這也解決了此問題。

+1

謝謝..它幫助.. :) – 2016-05-18 15:25:57

+1

工程就像一個魅力! 必須是被接受的答案) – 2016-08-23 12:58:08

+1

最優雅的解決方案,應該是被接受的答案 – Andriy 2017-02-14 20:25:55

6
public class MyTextWatcher implements TextWatcher { 
    private EditText et; 

    // Pass the EditText instance to TextWatcher by constructor 
    public MyTextWatcher(EditText et) { 
     this.et = et; 
    } 

    @Override 
    public void afterTextChanged(Editable s) { 
     // Unregister self before setText 
     et.removeTextChangedListener(this); 

     et.setText("text"); 

     // Re-register self after setText 
     et.addTextChangedListener(this); 
    } 
} 

用法:

et_text.addTextChangedListener(new MyTextWatcher(et_text)); 

更新:

爲了更順利地更新文本,取代

et.setText("text"); 

s.replace(0, s.length(), "text"); 
+0

爲什麼這是低調?這是我的問題的完美解決方案,而其他人沒有工作。我將添加它沒有必要爲此解決方案的子類TextWatcher然而。感謝陳淳他。 – 2016-07-07 21:22:33

+0

您的註銷和重新註冊TextWatcher的想法很好。但是,儘管et.setText(「」)起作用,但s.replace(0,s.length(),「」)不會。 – stevehs17 2017-07-27 22:14:09

+0

@ stevehs17,我真的不知道你的代碼如何,但使用更新得非常詳細,請嘗試一下。 – 2017-07-28 05:35:12

0

我已經創建了一個抽象類,它可以緩解通過TextWatcher對EditText進行修改時的循環問題。

/** 
* An extension of TextWatcher which stops further callbacks being called as a result of a change 
* happening within the callbacks themselves. 
*/ 
public abstract class EditableTextWatcher implements TextWatcher { 

    private boolean editing; 

    @Override 
    public final void beforeTextChanged(CharSequence s, int start, int count, int after) { 
     if (editing) 
      return; 

     editing = true; 
     try { 
      beforeTextChange(s, start, count, after); 
     } finally { 
      editing = false; 
     } 
    } 

    abstract void beforeTextChange(CharSequence s, int start, int count, int after); 

    @Override 
    public final void onTextChanged(CharSequence s, int start, int before, int count) { 
    if (editing) 
     return; 

     editing = true; 
     try { 
      onTextChange(s, start, before, count); 
     } finally { 
      editing = false; 
     } 
    } 

    abstract void onTextChange(CharSequence s, int start, int before, int count); 

    @Override 
    public final void afterTextChanged(Editable s) { 
     if (editing) 
      return; 

     editing = true; 
     try { 
      afterTextChange(s); 
     } finally { 
      editing = false; 
     } 
    }  

    public boolean isEditing() { 
     return editing; 
    } 

    abstract void afterTextChange(Editable s); 
} 
1

嗨,如果你需要把注意力集中在EditText變化的文字,你可以請求將焦點。這對我有效:

if (getCurrentFocus() == editText) { 
    editText.clearFocus(); 
    editText.setText("..."); 
    editText.requestFocus(); 
} 
相關問題