EditText: Differentiate between text change by set

2019-02-11 20:59发布

问题:

I have an EditText View which is edited by setText() from my code and by the user via (soft/hard) keyboard and - if possible by speech input. I want to handle input made by my code in another way than normal user input: if a user input happens, a internal event shall be fired. But I don't know how to differentiate between both. Previously - when developing on the emulator - I used the onKeyDown() method to catch user input. However, when testing on a real device, I found out, that onKeyDown() isn't triggered from soft keyboard input. Additionally speech input wouldn't be recognized by this, though I consider this to be a minor flaw. So that solution is no option for me.

On the other hand there is the onTextChanged() method, but this is triggered by both setText() and keyboard input. So how can I differentiate between both or which method is only called by user input, but not when using setText(), so can I overwrite it?

回答1:

I finally solved the problem by implementing a InputConnectionWrapper (see this question and particularly the answer for an implementation example) which has various methods to get the input from a soft-keyboard. I return my InputConnectionWrapper in the method EditText.onCreateInputConnection(). For hard keyboards I use EditText.onPreIme(). All these methods are overwritten and route their input through my framework which handles the text input and updates the View accordingly. This means, in all these overwritten methods (except for onCreateInputConnection()) the super method is not called cause I update the View myself. This prevents inconsistencies between my data model and the View.



回答2:

I believe android do not let you to distinguash between programmatically and manually entered text. The only workaround fo you as to use some sla that will indicate when test was set by your code, because you are always know when you call setText().



回答3:

You can use a flag to differentiate.

((EditText) rootView.findViewById(R.id.editText1)).addTextChangedListener(new TextWatcher() {
        public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void afterTextChanged(Editable editable) {
            update(true);
        }
    });            

private boolean updating = false;

private void update(boolean multiply) {
    if(updating){
        return;
    }
    updating = true;
    EditText editText1 = (EditText) getView().findViewById(R.id.editText1);
    editText1.setText("XXX");
    updating = false;
}


回答4:

I was having this issue when rotating the device. My editText is inside a dialog. Here's how I solved it:

editText.addTextChangedListener(
    new TextWatcher() {

        @Override
        public void afterTextChanged(Editable s) {
            String newValue = s.toString();

           String oldValue = (String) editText.getTag();

            if (newValue.length() > 0) {
                editText.setTag(newValue);
            }

            boolean itReallyChanged = oldValue != null && !newValue.equals(oldValue) && !newValue.isEmpty();
            if (itReallyChanged) {
                // Pretty sure the user genuinely changed this value,
                // not the device rotation
            }
        }
    }
);