11

I am using a TextInputLayout with the new function from the Support Library: passwordToggleEnabled. This gives a nice "eye"-icon that lets the user toggle password visibility on and off.

My question is if there is a way to use this functionality but start with password visible?

My xml:

<android.support.design.widget.TextInputLayout
                    android:id="@+id/password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:passwordToggleEnabled="true">

                    <EditText
                        android:id="@+id/password_edit"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="@string/prompt_password"
                        android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>

The toggle looks similar to this: enter image description here

I have not found a way to do this in xml, and not a way to manually toggle the visibility after the view is rendered. If I set the input type of the EditText to textVisiblePassword, the toggle is not shown. If I do it in code using for instance mPasswordEditText.setTransformationMethod(null); the password is shown but the toggle is gone and the user can't hide the password again. I know I can do it all manually but just wondering if I can make it work with the new magic toggle

Gober
  • 3,632
  • 3
  • 26
  • 33

10 Answers10

5

Easiest way is below Another solution is at last of this answer

private void setupPasswordToggleView() {
    final TextInputLayout textInputLayout = mRootView.findViewById(R.id.password);

    // You can skip post-call and write directly the code which is inside run method.
    // But to be safe (as toggle-view is child of TextInputLayout, post call
    // has been added.
    textInputLayout.post(new Runnable() {
        @Override
        public void run() {
            CheckableImageButton passwordToggleView = textInputLayout.findViewById(R.id.text_input_password_toggle);
            // passwordToggleView.toggle(); // Can not use as restricted to use same library group
            // passwordToggleView.setChecked(true); // Can not use as restricted to use same library group
            passwordToggleView.performClick();
        }
    });
}

Now let me explain the answer

While looking into code of TextInputLayout.java I found that, there is a layout design_text_input_password_icon.xml which is being added to TextInputLayout.java. Below is that code

private void updatePasswordToggleView() {
    if (mEditText == null) {
        // If there is no EditText, there is nothing to update
        return;
    }
    if (shouldShowPasswordIcon()) {
        if (mPasswordToggleView == null) {
            mPasswordToggleView = (CheckableImageButton) LayoutInflater.from(getContext())
                    .inflate(R.layout.design_text_input_password_icon, mInputFrame, false);
            mPasswordToggleView.setImageDrawable(mPasswordToggleDrawable);
            mPasswordToggleView.setContentDescription(mPasswordToggleContentDesc);
            mInputFrame.addView(mPasswordToggleView); // << HERE IS THAT
            .........
}

Now next target was to find design_text_input_password_icon.xml and lookup id of the toggle view. So found the layout design_text_input_password_icon.xml here and it has written as

18<android.support.design.widget.CheckableImageButton
19    xmlns:android="http://schemas.android.com/apk/res/android"
20    android:id="@+id/text_input_password_toggle"
21    android:layout_width="wrap_content"
22    android:layout_height="wrap_content"
23    android:layout_gravity="center_vertical|end|right"
24    android:background="?attr/selectableItemBackgroundBorderless"
25    android:minHeight="48dp"
26    android:minWidth="48dp"/>

I found the id text_input_password_toggle of that view and now everything was easy to just find that view in it's viewgroup and perform action on that.


Another solution would be to iterate childs of TextInputLayout and check if it is CheckableImageButton and then perform click on it. By this way there would not be dependancy on id of that view and if Android changes the id of view, our solution will still work. (Although they do not change id of a view in normal cases).

private void setupPasswordToggleViewMethod2() {
    final TextInputLayout textInputLayout = mRootView.findViewById(R.id.password);

    textInputLayout.post(new Runnable() {
        @Override
        public void run() {

            View toggleView = findViewByClassReference(textInputLayout, CheckableImageButton.class);
            if (toggleView != null) {
                toggleView.performClick();
            }
        }
    });
}

Where findViewByClassReference(View rootView, Class<T> clazz) original utility class is defined as below

public static <T extends View> T findViewByClassReference(View rootView, Class<T> clazz) {
    if(clazz.isInstance(rootView)) {
        return clazz.cast(rootView);
    }
    if(rootView instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) rootView;
        for(int i = 0; i < viewGroup.getChildCount(); i++) {
            View child = viewGroup.getChildAt(i);
            T match = findViewByClassReference(child, clazz);
            if(match != null) {
                return match;
            }
        }
    }
    return null;
}
Pankaj Kumar
  • 81,967
  • 29
  • 167
  • 186
  • Some comment on your first solution - `R.id.text_input_password_toggle` is not a public id. – Cheok Yan Cheng Jul 11 '18 at 16:50
  • @CheokYanCheng Solution I posted a few days ago finds the view without using the id, using the content description instead – Tyler V Jul 12 '18 at 00:43
  • @CheokYanCheng I did not get public-id concept. And if you are talking about the id which is declared in the layout created by Android itself, then I would say that is fine to use that id if you know and your solution will work until they do not change the id. This is similar to the old-styled listview example where we were giving id of listview what was declared by android. And there are many examples where we use such ids. But can you please explain public-id if I did not get it? – Pankaj Kumar Jul 12 '18 at 04:58
  • 4
    In 2019, there's a public method called `passwordVisibilityToggleRequested()` on `TextInputLayout` that does this for you. – kos Jun 25 '19 at 02:40
2

Just removing android:inputType="textPassword" worked for me

Aziz
  • 1,976
  • 20
  • 23
1

With the Material Components Library (1.1.0 , 1.2.0-beta01, 1.3.0-alpha01) to start with a visible password just use:

<com.google.android.material.textfield.TextInputLayout
    app:endIconMode="password_toggle"
/>

and in your code:

textInputLayout.getEditText().setTransformationMethod(null);

If you want to return to the default behavior:

textInputLayout.getEditText()
    .setTransformationMethod(PasswordTransformationMethod.getInstance());
Boken
  • 4,825
  • 10
  • 32
  • 42
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
0

One of the ways is, we can search CheckableImageButton from TextInputLayout, and then programmatically perform onClick on it, based on the password visibility status of EditText.

Here's the code snippet.

private CheckableImageButton findCheckableImageButton(View view) {
    if (view instanceof CheckableImageButton) {
        return (CheckableImageButton)view;
    }

    if (view instanceof ViewGroup) {
        ViewGroup viewGroup = (ViewGroup) view;
        for (int i = 0, ei = viewGroup.getChildCount(); i < ei; i++) {
            CheckableImageButton checkableImageButton = findCheckableImageButton(viewGroup.getChildAt(i));
            if (checkableImageButton != null) {
                return checkableImageButton;
            }
        }
    }

    return null;
}

//...

if (passwordEditText.getTransformationMethod() != null) {
    CheckableImageButton checkableImageButton = findCheckableImageButton(passwordTextInputLayout);
    if (checkableImageButton != null) {
        // Make password visible.
        checkableImageButton.performClick();
    }
}
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
0

I was able to get it to start in clear-text mode with the following bit of code. Basically, I had to find the right View using the content description.

If they provided a setter method for mPasswordToggledVisibility that would make things a lot easier...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextInputLayout til = findViewById(R.id.password);
    CharSequence cs = til.getPasswordVisibilityToggleContentDescription();
    ArrayList<View> ov = new ArrayList<>();
    til.findViewsWithText(ov, cs,View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
    if( ov.size() == 1 ) {
        Checkable c = (Checkable)ov.get(0);
        // As far as I can tell the check for "isChecked" here isn't needed,
        // since it always starts unchecked by default. However, if you
        // wanted to check for state, you could do it this way.
        if( c != null && !c.isChecked()) {
            ov.get(0).performClick();
        }
    }
}
Tyler V
  • 9,694
  • 3
  • 26
  • 52
0

You can use the bellow code:

TextInputLayout yourTextInputLayoutId = findViewById(R.id.yourTextInputLayoutId);
FrameLayout frameLayout = (FrameLayout) (yourTextInputLayoutId).getChildAt(0);

CheckableImageButton checkableImageButton = (CheckableImageButton) frameLayout.getChildAt(1);
checkableImageButton.performClick();

Here yourTextInputLayoutId is your TextInputLayout id from xml.

Boken
  • 4,825
  • 10
  • 32
  • 42
Anisuzzaman Babla
  • 6,510
  • 7
  • 36
  • 53
0

try this

if (inputEditText.getTransformationMethod() == null) {
    inputEditText.setTransformationMethod(new PasswordTransformationMethod());
} else {
    inputEditText.setTransformationMethod(null);
}


inputEditText.setSelection(inputEditText.getText().length());
Boken
  • 4,825
  • 10
  • 32
  • 42
Nithesh
  • 206
  • 3
  • 8
0

To start with Password visible, Do not include

android:inputType="textPassword"

In

<com.google.android.material.textfield.TextInputEditText>
.... 

</com.google.android.material.textfield.TextInputEditText>
Boken
  • 4,825
  • 10
  • 32
  • 42
oriohac
  • 187
  • 1
  • 8
0

You can add in your xml file in TextInputLayout passwordToggleEnabled="true" passwordToggleDrawable=""@drawable/show_password_selector"

and make your show_password_selector.xml

this will look the same as the picture you sent

-1

You can use:

yourEditText.setTransformationMethod(new PasswordTransformationMethod());

To re-show the readable password, just pass null as transformation method:

yourEditText.setTransformationMethod(null);

so user can hide it again.

user694733
  • 15,208
  • 2
  • 42
  • 68
Sejal Baraiya
  • 238
  • 2
  • 9
  • Thanks for the answer, but this also makes the toggle button disappear. I have expanded my question to make it clear what is not working. – Gober Jan 12 '17 at 12:15