टेक्स्ट वॉचर को ट्रिगर किए बिना मैं एडिट टेक्स्ट को कैसे बदल सकता हूं?


104

मेरे पास EditTextइस पर ग्राहक टेक्स्ट वॉचर के साथ एक फ़ील्ड है। कोड के एक टुकड़े में मुझे EditText में मूल्य को बदलना होगा जो मैं उपयोग कर रहा हूं .setText("whatever")

समस्या यह है कि जैसे ही मैं बदलाव करता हूं, afterTextChangedविधि बदल जाती है जिसे एक अनंत लूप बनाया जाता है। इसके बाद पाठ को कैसे बदला जा सकता है, इसके बाद क्या होगा?

मैं पाठ के बाद पाठ विधि की जरूरत है ताकि हटाने का सुझाव न दें TextWatcher

जवाबों:


70

आप पहरेदार को अपंजीकृत कर सकते हैं, और फिर उसे फिर से पंजीकृत कर सकते हैं।

वैकल्पिक रूप से, आप एक ध्वज सेट कर सकते हैं ताकि आपका चौकीदार यह जान सके कि आपने अभी-अभी पाठ को स्वयं बदला है (और इसलिए इसे अनदेखा करना चाहिए)।


आपका इशारा मेरे लिए काफी है। असल में मैं श्रोता को onResume में पंजीकृत कर रहा था लेकिन onPause () में डी-रजिस्टरिंग नहीं कर रहा था, इसलिए यह कई बार कॉल कर रहा था।
12

किसी को समझा सकते हैं? तकनीकी रूप से, मैं Android में नया हूँ, और अधिक विस्तार की जरूरत है pls, धन्यवाद।
बूडी मुलियो

116

संक्षिप्त जवाब

आप यह देख सकते हैं कि किस दृश्य में वर्तमान में उपयोगकर्ता और प्रोग्राम ट्रिगर घटनाओं के बीच अंतर करने के लिए फ़ोकस है।

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

myEditText.addTextChangedListener(new TextWatcher() {

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

    //...
});

लंबा जवाब

संक्षिप्त उत्तर के अतिरिक्त: यदि आपके myEditTextपास उस प्रोग्राम को बदलने के लिए पहले से ही फोकस है, जिसे आपको कॉल करना चाहिए clearFocus(), तो आप कॉल करते हैं setText(...)और आपके द्वारा फ़ोकस का पुनः अनुरोध करने के बाद। यह एक उपयोगी कार्य में एक अच्छा विचार होगा:

void updateText(EditText editText, String text) {
    boolean focussed = editText.hasFocus();
    if (focussed) {
        editText.clearFocus();
    }
    editText.setText(text);
    if (focussed) {
        editText.requestFocus();
    }
}

कोटलिन के लिए:

चूंकि कोटलिन विस्तार कार्यों का समर्थन करता है इसलिए आपकी उपयोगिता फ़ंक्शन इस तरह दिख सकती है:

fun EditText.updateText(text: String) {
    val focussed = hasFocus()
    if (focussed) {
        clearFocus()
    }
    setText(text)
    if (focussed) {
        requestFocus()
    }
}

टुकड़ा getActivity().getCurrentFocus()और कोटलिन मेंactivity?.currentFocus
मोहम्मद रज़ा ख़ानी

@ मोहम्मदरेज़ाखानी अरे! आपको इसकी आवश्यकता नहीं है आप hasFocus()सीधे कॉल कर सकते हैं EditText
विली मेंजेल

आदर्श नहीं। क्या होगा अगर मैं ट्रिगर श्रोता के बिना सेटटेक्स्ट () को संपादित करना चाहता हूं, भले ही एडिटेक्स फोकस हो?
जया प्रकाश

31
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 update
        et.removeTextChangedListener(this);

        // The trick to update text smoothly.
        s.replace(0, s.length(), "text");

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

उपयोग:

et_text.addTextChangedListener(new MyTextWatcher(et_text));

जब तेजी से पाठ दर्ज करता है, तो आप उपयोग कर रहे आप एक छोटा सा अंतराल महसूस कर सकते हैं ) editText.setText ( के बजाय editable.replace ()


इसे क्यों ठुकरा दिया गया? यह मेरी समस्या का सही समाधान है जबकि दूसरों के काम नहीं आया। मैं यह जोड़ना चाहूंगा कि हालांकि इस समाधान के लिए TextWatcher को उपखंड करना आवश्यक नहीं है। धन्यवाद चान चुन हिम।
माइकल फुल्टन

TextWatcher को अनरिजर्व करने और रिरेगिस्टर करने के लिए आपका विचार बहुत काम आता है। हालांकि, जबकि et.setText ("") काम करता है, s.replace (0, s.length (), "" नहीं करता है।
stevehs17

@ stevehs17, मुझे वास्तव में नहीं पता है कि आपका कोड कैसा है लेकिन उपयोग को अधिक विस्तृत रूप से अपडेट किया गया था, एक कोशिश करें।
चून हिम

15

ठीक करने के लिए आसान ट्रिक ... जब तक नए एडिट टेक्स्ट वैल्यू को प्राप्त करने का आपका तर्क बेकार है (जो शायद यह होगा, लेकिन सिर्फ कह रहा है)। आपकी श्रोता विधि में, यदि वर्तमान मूल्य पिछली बार के मूल्य से अलग है, तो केवल संपादन पाठ को संशोधित करें।

जैसे,

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
यह अभी भी दो बार बुलाया जा रहा विधि में परिणाम होगा, नहीं?
ट्रेवर हार्ट

हां, यही कारण है कि मैंने कहा कि यह निष्कलंक होना चाहिए (अधिक स्पष्ट होना चाहिए) ... आदर्श नहीं है लेकिन आपको वास्तव में कट्टर अनुकूलन करना होगा यदि आप एक एकल विधि कॉल के ओवरहेड के बारे में चिंतित हैं जो कोई काम नहीं करता है। यदि हां, तो आप कॉल करने से पहले श्रोता को हटाने के लिए कोड को फिर से व्यवस्थित कर सकते हैं setText()और इसके बाद इसे फिर से जोड़ सकते हैं।
जेफरी ब्लाटमैन 16

6

मैं इस तरह से उपयोग करता हूं:

mEditText.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 (mEditText.isFocused()) { //<-- check if is focused 
                    mEditText.setTag(true);
                }
            }
        });

और हर बार जब आपको पाठ को प्रोग्रामेटिक रूप से बदलने की आवश्यकता होती है, तो पहले फोकस को साफ़ करें

mEditText.clearFocus();
mEditText.setText(lastAddress.complement);

5

इसके लिए जेनेरिक समाधान के लिए आप कोटलिन DSL सिंटैक्स का उपयोग कर सकते हैं:

fun TextView.applyWithDisabledTextWatcher(textWatcher: TextWatcher, codeBlock: TextView.() -> Unit) {
    this.removeTextChangedListener(textWatcher)
    codeBlock()
    this.addTextChangedListener(textWatcher)
}

और अपने TextWatcher के अंदर, आप इसका उपयोग कर सकते हैं:

editText.applyWithDisabledTextWatcher(this) {
    text = formField.name
}

बहुत क्लीनर। कोटलीन डीएसएल कमाल है
अंजल सनीन

4

यह मेरे लिए अच्छा काम करता है

EditText inputFileName; // = (EditText)findViewbyId(R.id...)
inputFileName.addTextChangedListener(new TextWatcher() {
        public void afterTextChanged(Editable s) {

            //unregistering for event in order to prevent infinity loop
            inputFileName.removeTextChangedListener(this);

            //changing input's text
            String regex = "[^a-z0-9A-Z\\s_\\-]";
            String fileName = s.toString();
            fileName = fileName.replaceAll(regex, "");
            s.replace(0, s.length(), fileName); //here is setting new text

            Log.d("tag", "----> FINAL FILE NAME: " + fileName);

            //registering back for text changes
            inputFileName.addTextChangedListener(this);
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        public void onTextChanged(CharSequence s, int start, int before, int count) { }
    });

3

का उपयोग करके समस्या को आसानी से हल किया जा सकता है tag दायर और आपको editText के फ़ोकस से भी निपटने की ज़रूरत नहीं है।

पाठ और टैग को प्रोग्रामेटिक रूप से सेट करना

editText.tag = "dummyTag"
editText.setText("whatever")
editText.tag = null

tagOnTextChanged में जाँच हो रही है

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    if (editText.tag == null) {
       // your code
    }
}

3

यदि आपको EditTextपरिवर्तन पाठ पर ध्यान केंद्रित करने की आवश्यकता है तो आप ध्यान देने का अनुरोध कर सकते हैं:

if (getCurrentFocus() == editText) {
    editText.clearFocus();
    editText.setText("...");
    editText.requestFocus();
}

1

इस तर्क को आज़माएं: मैं अनंत लूप में जाए बिना ("") सेट करना चाहता था और यह कोड मेरे लिए काम करता है। मुझे आशा है कि आप अपनी आवश्यकता के अनुसार इसे संशोधित कर सकते हैं

        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
        }
    });

1

यहां एक आसान वर्ग है जो टेक्स्टवैचर की तुलना में एक सरल इंटरफ़ेस प्रदान करता है जो कि होने वाले परिवर्तनों को देखने के सामान्य मामले के लिए चाहते हैं। यह ओपी के अनुरोध के अनुसार अगले बदलाव की अनदेखी करने की भी अनुमति देता है।

public class EditTexts {
    public final static class EditTextChangeListener implements TextWatcher {
        private final Consumer<String> onEditTextChanged;
        private boolean ignoreNextChange = false;
        public EditTextChangeListener(Consumer<String> onEditTextChanged){
            this.onEditTextChanged = onEditTextChanged;
        }
        public void ignoreNextChange(){
            ignoreNextChange = true;
        }
        @Override public void beforeTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void onTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void afterTextChanged(Editable s) {
            if (ignoreNextChange){
                ignoreNextChange = false;
            } else {
                onEditTextChanged.accept(s.toString());
            }
        }
    }
}

इसे इस तरह उपयोग करें:

EditTexts.EditTextChangeListener listener = new EditTexts.EditTextChangeListener(s -> doSomethingWithString(s));
editText.addTextChangedListener(listener);

जब भी आप editTextपुनरावर्ती संपादन के एक झरना के बिना सामग्री को संशोधित करना चाहते हैं , तो यह करें:

listener.ignoreNextChange();
editText.setText("whatever"); // this won't trigger the listener

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

मैंने एक अमूर्त वर्ग बनाया है जो कि जब TextTexter के माध्यम से 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);
}

0

बहुत ही सरल, इस विधि के साथ पाठ सेट करें

void updateText(EditText et, String text) {
   if (!et.getText().toString().equals(text))
       et.setText(text);
}

-2

आपको यह सुनिश्चित करना चाहिए कि पाठ परिवर्तनों का आपका कार्यान्वयन स्थिर है और यदि कोई परिवर्तन आवश्यक नहीं है तो पाठ को नहीं बदलता है। आम तौर पर वह कोई भी सामग्री होगी जो पहले से ही एक बार वॉचर के माध्यम से होती है।

सबसे आम गलती यह है कि संबंधित एडिट टेक्स्ट या एडिटेबल में एक नया टेक्स्ट सेट करना है, हालांकि टेक्स्ट वास्तव में परिवर्तन नहीं था।

उसके शीर्ष पर, यदि आप कुछ विशिष्ट दृश्य के बजाय संपादन योग्य में अपना परिवर्तन करते हैं, तो आप आसानी से अपने द्रष्टा को अस्वीकार कर सकते हैं, और यह भी सुनिश्चित कर सकते हैं कि कुछ इकाई परीक्षणों के साथ अलगाव में यह सुनिश्चित कर सके कि आपको इसका परिणाम चाहिए।

चूँकि एडिटेबल एक ऐसा इंटरफ़ेस है, जिसका उपयोग आप डमी कार्यान्वयन के लिए भी कर सकते हैं जो एक रनटाइम एक्सप्रेशन को फेंकता है यदि इसके किसी भी तरीके को कहा जाता है जो इसकी सामग्री को बदलने की कोशिश करता है, जब सामग्री का परीक्षण करना चाहिए जो स्थिर होना चाहिए।


-2

बात करने का मेरा तरीका:

लेखन सेगमेंट में

        EditText e_q;

        e_q = (EditText) parentView.findViewWithTag("Bla" + i);

        int id=e_q.getId();
        e_q.setId(-1);
        e_q.setText("abcd...");
        e_q.setId(id);

श्रोता

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

        int id = view.getId();
        if(id==-1)return;

        ....

वैसे भी काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.