programing

텍스트 워처를 트리거하지 않고 텍스트 편집 텍스트를 변경하려면 어떻게 해야 합니까?

sourcetip 2022. 10. 28. 23:04
반응형

텍스트 워처를 트리거하지 않고 텍스트 편집 텍스트를 변경하려면 어떻게 해야 합니까?

는 i i나 an an an i i i i i i i 。EditText[고객님의 문자 감시자] [ [ [ [ [ [ 。. EditText는 EditText를 합니다..setText("whatever").

는 그것을 입니다.afterTextChanged무한 루프를 생성한 메서드가 호출됩니다.텍스트 변경 후 트리거되지 않고 텍스트를 변경하려면 어떻게 해야 합니까?

에 afterTextChanged는 TextWatcher.

단답

현재 어떤 보기가 사용자 및 프로그램 트리거 이벤트를 구분하는 데 초점을 두고 있는지 확인할 수 있습니다.

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

Kotlin의 경우:

Kotlin은 확장 기능을 지원하므로 유틸리티 기능은 다음과 같습니다.

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

워처의 등록을 해제하고 나서, 재등록할 수 있습니다.

또는 워처가 텍스트를 직접 변경한 시점을 알 수 있도록 플래그를 설정할 수도 있습니다(따라서 무시해야 함).

자바:

public class MyTextWatcher implements TextWatcher {
    private EditText editText;

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

    @Override
    public void afterTextChanged(Editable e) {
        // Unregister self before update
        editText.removeTextChangedListener(this);

        // The trick to update text smoothly.
        e.replace(0, e.length(), e.toString());

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

    ...
}

코틀린:

class MyTextWatcher(private val editText: EditText) : TextWatcher {

  override fun afterTextChanged(e: Editable) {
    editText.removeTextChangedListener(this)
    e.replace(0, e.length, e.toString())
    editText.addTextChangedListener(this)
  }

  ...
}

사용방법:

et_text.addTextChangedListener(new MyTextWatcher(et_text));

editable.replace() 대신 editText.setText()를 사용하는 경우 텍스트를 빠르게 입력할 때 약간의 지연을 느낄 수 있습니다.

수정하기 쉬운 트릭... 새로운 편집 텍스트 값을 도출하는 논리가 무의미할 경우(아마도 그럴 것입니다만, 그렇다고는 할 수 없습니다.수신기 방법에서는 현재 값이 마지막으로 값을 수정한 시간과 다른 경우에만 편집 텍스트를 수정하십시오.

예.,

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

Kotlin DSL 구문을 사용하면 다음과 같은 범용 솔루션을 사용할 수 있습니다.

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

TextWatcher에서는 다음과 같이 사용할 수 있습니다.

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

저는 이렇게 씁니다.

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

는 '어리다'를 사용하면 쉽게 할 수 .tag도 할 수 할 가 없습니다.텍스트의 초점

프로그래밍 방식으로 텍스트 및 태그 설정

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

의 중'tagin onTextChanged

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

이거면 되네

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

on stay if if if if if if if if on on on on on 할 필요가 있는 경우EditText포커스를 요청할 수 있는 텍스트 변경:

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

이렇게 하면 쉽다

editText.addTextChangedListener(object : TextWatcher {

        private var isEditing = false

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {


        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

        }

        override fun afterTextChanged(s: Editable?) {
            if(!isEditing){
                isEditing = true
                editText.setText("Hello World!")
                isEditing = false
            }

        }
    })

이렇게 하면 무한 루프에 저장되지 않는다

다음 논리를 사용해 보십시오.무한 루프를 하지 않고 Text("")를 설정하려고 했는데, 이 코드를 사용할 수 있습니다.당신의 요구에 맞게 이것을 수정해 주셨으면 합니다.

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

이것은 TextWatcher보다 간단한 인터페이스를 제공하는 편리한 클래스입니다.이러한 클래스는 변경이 발생했을 때 변경을 확인하는 일반적인 경우에 적합합니다.또한 OP가 요청한 대로 다음 변경을 무시할 수도 있습니다.

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

마이 베리안트:

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()를 덮어쓰려고 했는데 최종입니다).

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

매우 간단합니다. 이 방법으로 텍스트를 설정합니다.

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

다른 솔루션과 마찬가지로 뷰바인딩을 사용하여 커스텀 스핀을 합니다.

다음 TextWatcher를 만들었습니다.

class ControlledTextWatcher(
    private val parent: TextView,
    private val onChange: ((text: CharSequence?, start: Int, before: Int, count: Int) -> Unit)?,
    private val beforeChange: ((text: CharSequence?, start: Int, count: Int, after: Int) -> Unit)? = null,
    private val afterChange: ((editable: Editable?) -> Unit)? = null
) : TextWatcher {
    init {
        parent.addTextChangedListener(this)
    }

    private var enabled = true

    var text: String?
        get() = parent.value
        set(value) {
            this.enabled = false
            parent.text = value
            this.enabled = true
        }

    var res: Int
        get() = throw RuntimeException("String resource cannot be retrieved after being set")
        set(value) {
            parent.text = parent.context.getString(value)
        }


    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        if (enabled)
            beforeChange?.invoke(s, start, count, after)
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        if (enabled)
            onChange?.invoke(s, start, before, count)
    }

    override fun afterTextChanged(s: Editable?) {
        if (enabled)
            afterChange?.invoke(s)
    }

    fun detach() {
        parent.removeTextChangedListener(this)
    }
}

주로 뷰바인딩에 사용합니다.

클래스 TestActivity : AppCompatActivity() {

class TestActivity : AppCompatActivity() {
    private lateinit var binding: ActivityTestBinding
    private val edit by lazy { ControlledTextWatcher(binding.text, this::textChanged }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTestBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

내가 하고 싶을 때EditText 용 the the the를 .text ""res「」의 ControlledTextWatcher다음과 같이 합니다.

edit.text = "hello world" //this does not trigger the text watcher

, 가 「」를 는,EditText합니다.

도 이 할 필요가 .EditText 둘 중 돼요.EditText 또는 를 ""에 합니다.ControlledTextWatcher

해야 돼요.afterChange because because because because because because the the the the because because because because because because because because because because because 에 게시되어 있기 때문입니다.TextView 끝없는 가 될 도 있어요.

텍스트 변경 구현이 안정적이고 변경이 필요하지 않은 경우 텍스트를 변경하지 않도록 해야 합니다.일반적으로 이 콘텐츠는 이미 한 번 워처를 통과한 콘텐츠입니다.

텍스트가 실제로 변경되지 않았더라도 연관된 EditText 또는 Editable에서 새 텍스트를 설정하는 것이 가장 일반적인 실수입니다.

또한 특정 보기 대신 편집 가능을 변경하면 워처를 쉽게 다시 사용할 수 있습니다. 또한 일부 장치 테스트를 통해 워처를 분리하여 테스트하여 원하는 결과를 얻을 수 있습니다.

Editable은 인터페이스이기 때문에 Runtime을 슬로우하는 더미 구현을 사용할 수도 있습니다.안정적인 콘텐츠를 테스트할 때 콘텐츠 변경을 시도하는 메서드가 호출된 경우 예외입니다.

내 방식:

쓰기 세그먼트

        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;

        ....

어쨌든 작동한다.

언급URL : https://stackoverflow.com/questions/9385081/how-can-i-change-the-edittext-text-without-triggering-the-text-watcher

반응형