How to mask text in EditText when the view loses focus.

Viewed 1121

So if a user enters "1234" they will see "1234" in the EditText field. but when that field loses focus I want it to show "****"

So I've implemented a custom TransformationMethod that will only mask the entered text if the EditText field does not have focus.

when I enter the text "12345" it shows it as it should "12345" but when I click on a different field the numbers never get masked. I want to see "*****" but I still see the same "12345"

If I rotate the device though (force it to reload everything) it correctly shows "*****". And when I click on the EditText Field it correctly changes the masked text from "*****" to "12345" So it works when gaining focus but not when losing focus. I've tried implementing an OnFocusChangeListener but it seems to have no affect.

Is there any way I can force the EditText Field to redraw the text when it loses focus?

SetUp:

 editText.setTransformationMethod(CustomPasswordTransformationMethod(numUnobfuscatedDigits))
editText.setOnFocusChangeListener { view, hasFocus ->
                    ((EditText)view).invalidate()    
                     ((EditText)view).refreshDrawableState()                    

CustomPasswordTransformationMethod: public class CustomPasswordTransformationMethod extends PasswordTransformationMethod { private int unObfuscated = 1; private boolean mIsFocused = false;

    /**
     * @param number the number of digits that will be unObfuscated at the end of the input string. Must be a positive integer or 0.
     */
    public CustomPasswordTransformationMethod(int number) {
        if (number < 0) {
            Log.e(TAG, "Invalid parameter number =" + number + " number of un-obfuscated digits must be a positive integer or 0.");
            unObfuscated = 0;
        }
        unObfuscated = number;
    }

    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        return new PasswordCharSequence(source);
    }

    @Override
    public void onFocusChanged(View view, CharSequence sourceText,
                               boolean focused, int direction,
                               Rect previouslyFocusedRect) {
        super.onFocusChanged(view,sourceText,focused, direction, previouslyFocusedRect);
        mIsFocused = focused;
    }


    private class PasswordCharSequence implements CharSequence {
        private CharSequence mSource;

        public PasswordCharSequence(CharSequence source) {
            mSource = source; // Store char sequence
        }

        public char charAt(int index) {
            if(mIsFocused) return mSource.charAt(index);
            else {
                if (index < ((length()) - unObfuscated)) return '●';
                return mSource.charAt(index);
            }
        }

        public int length() {
            return mSource.length(); // Return default
        }

        public CharSequence subSequence(int start, int end) {
            return mSource.subSequence(start, end); // Return default
        }
    }
};
2 Answers

Try this and see if it does what you need.

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean hasFocus) {
        if(hasFocus){
            editText.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
        }
        else{
            editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
        }
    }
});

Maybe you can try to keep it simple:

String password = "";

editText.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean hasFocus) {
        if (hasFocus) {
            editText.setText(password, TextView.BufferType.EDITABLE);
        } else {
            password = editText.getText().toString();
            String ofuscated = "";
            for (int i = 0; i < password.length(); i++){ ofuscated += "*"; }
            editText.setText(ofuscated, TextView.BufferType.EDITABLE);
        }
    }
});
Related