Enhanced password input view: toggle the visibility of the password.
Hey! I decided to proceed with blogging after a delay to share more things about Android development. Today let's start with a simple one: password input field.
Enhanced password input.
Usually, sign in or sign up UI forms have some input field for password. And Android SDK provides a simple way to have input field with hidden characters: EditText
with inputType="textPassword"
. Very simple. However, if you need to type some long and complex password this could be a little bit tedious: it's quite easy to make a type and then you need to start password typing again.
Solution.
So to make password input easier we can implement a simple but very effective solution: show an icon at the right edge of an input field, when you tap down the icon - typed password becomes visible, when you lift finger up - it's again shows only obscured characters. Simple, effective and secure!
There are at least three obvious possible ways to achieve that:
compose default Android SDK views in a layout and put behaviour logic into a parent Fragment/Activity
make a composed ViewGroup to encapsulate layout and behaviour logic
make an EditText subclass that will manage custom drawable at the right side of the view
All that three ways will work good for you. Originally I've made with the 1st way for several reasons like:
I don't like to create extra entities without a real necessity in it. Something like Occam's razor principal. :)
I need to have it only in one place
Sure, if you need to have the same enhanced password views multiple times in different places choose 2nd or 3rd (preferable, cause view hierarchy is flat) options.
Implementation.
So the simplest implementation of the enhanced password view with default Android SDK views only could looks like that:
In a sign in XML layout (trivial and non topic related params like paddings are omitted):
<RelativeLayout
...>
<EditText
android:id="@+id/fragment_login_password"
android:inputType="textPassword"
.../>
<ImageView
android:id="@+id/fragment_login_password_visibility"
android:layout_alignRight="@+id/fragment_login_password"
android:clickable="true"
android:src="@drawable/ic_show_password"
.../>
</RelativeLayout>
In parent Fragment/Activity:
2.1. For good UX let's add a text changed listener to show password visibility if there is some typed password value and to hide it for empty password view:
mPasswordView.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) {
mPasswordVisibilityView.setVisibility(s.length() > 0 ? View.VISIBLE : View.GONE);
}
});
2.2. Set a touch listener for password visibility view to react on touches
mPasswordVisibilityView.setOnTouchListener(mPasswordVisibleTouchListener);
Touch listener apply visible characters mode if finger is down inside the visibility view, and apply original password mode back when finger is up or leaves the visibility view. Also we take care about persisting of cursor position, so user can switch visibility mode at any time without loosing current input cursor position.
private View.OnTouchListener mPasswordVisibleTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final boolean isOutsideView = event.getX() < 0 ||
event.getX() > v.getWidth() ||
event.getY() < 0 ||
event.getY() > v.getHeight();
// change input type will reset cursor position, so we want to save it
final int cursor = mPasswordView.getSelectionStart();
if (isOutsideView || MotionEvent.ACTION_UP == event.getAction())
mPasswordView.setInputType( InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_PASSWORD);
else
mPasswordView.setInputType( InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
mPasswordView.setSelection(cursor);
return true;
}
};
That's it! As I said it's very simple to implement, but it greatly improves UX!