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:
1. 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>
2. 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!
Alternatives.
You can easily adapt this solution for composed or custom views (2nd and 3rd options). Or just take a ready-made solutions by Cyril Mottier or by Edward Dale.
Fantastic. Thanks.
ReplyDelete