TextInputLayouts的可见密码passwordToggleEnabled

时间:2017-01-12 11:02:06

标签: android android-textinputlayout

我正在使用TextInputLayout和支持库中的新函数:passwordToggleEnabled。这提供了一个很好的眼睛" -icon,让用户可以打开和关闭密码可见性。

我的问题是,是否有办法使用此功能,但密码可见?

我的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>

切换看起来与此类似: enter image description here

我还没有找到在xml中执行此操作的方法,而不是在呈现视图后手动切换可见性的方法。如果我将EditText的输入类型设置为textVisiblePassword,则不会显示切换。如果我在代码中使用例如mPasswordEditText.setTransformationMethod(null);显示密码但切换消失,用户无法再次隐藏密码。我知道我可以手动完成所有操作,但只是想知道我是否可以使用新的魔术切换工作

9 个答案:

答案 0 :(得分:0)

其中一种方法是,我们可以根据CheckableImageButton的密码可见性状态,从TextInputLayout中搜索onClick,然后以编程方式对其执行EditText。 / p>

这是代码段。

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();
    }
}

答案 1 :(得分:0)

我能够用下面的代码让它以纯文本模式启动。基本上,我必须使用内容描述来找到正确的视图。

如果他们为mPasswordToggledVisibility提供了setter方法,这将使事情变得容易得多...

@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();
        }
    }
}

答案 2 :(得分:0)

最简单的方法是 另一种解决方案是此答案的最后

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();
        }
    });
}

  

现在让我解释一下答案

在查看TextInputLayout.java的代码时,我发现有一个布局design_text_input_password_icon.xml被添加到TextInputLayout.java中。下面是该代码

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
            .........
}

现在下一个目标是找到design_text_input_password_icon.xml和切换视图的查找ID。因此找到布局design_text_input_password_icon.xml here,它写为

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"/>

我找到了该视图的ID text_input_password_toggle,现在可以轻松地在视图组中找到该视图并对其执行操作。


另一种解决方案是迭代TextInputLayout的子项,并检查其是否为CheckableImageButton,然后对其进行单击。通过这种方式,就不会依赖于该视图的ID,并且如果Android更改了视图的ID,我们的解决方案仍然可以使用。 (尽管在正常情况下它们不会更改视图的ID)。

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();
            }
        }
    });
}

其中findViewByClassReference(View rootView, Class<T> clazz) original utility class 的定义如下

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;
}

答案 3 :(得分:0)

您可以动态更改TextView的属性。如果将XML Atrribute android:password设置为true,则如果将其设置为false,则视图将显示点。

使用方法setTransformationMethod,您应该可以从代码中更改此属性。 (免责声明:显示该视图后,我尚未测试该方法是否仍然有效。如果您遇到问题,请给我留言。)

完整的示例代码为

yourTextView.setTransformationMethod(new PasswordTransformationMethod());

隐藏密码。要显示密码,您可以设置现有的转换方法之一,或实现一个空的TransformationMethod,对输入文本不做任何操作。

yourTextView.setTransformationMethod(new DoNothingTransformation());

答案 4 :(得分:0)

您可以使用以下代码:

TextInputLayout yourTextInputLayoutId=findViewById(R.id.yourTextInputLayoutId);
       FrameLayout frameLayout= (FrameLayout) (yourTextInputLayoutId).getChildAt(0);
       CheckableImageButton checkableImageButton= (CheckableImageButton) frameLayout.getChildAt(1);
       checkableImageButton.performClick();

yourTextInputLayoutId是xml中的T​​extInputLayout ID。

答案 5 :(得分:0)

要首先显示可见的密码, 不包括

android:inputType="textPassword"

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

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

答案 6 :(得分:0)

使用材料成分库(1.1.01.2.0-beta011.3.0-alpha01)以可见的密码开头,只需使用:

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

以及您的代码中

textInputLayout.getEditText().setTransformationMethod(null);

如果要恢复默认行为:

textInputLayout.getEditText()
    .setTransformationMethod(PasswordTransformationMethod.getInstance());

答案 7 :(得分:0)

仅删除android:inputType="textPassword"对我有用

答案 8 :(得分:-2)

您可以使用:

yourEditText.setTransformationMethod(new PasswordTransformationMethod());

要重新显示可读密码,只需将null作为转换方法传递:

yourEditText.setTransformationMethod(null);

因此用户可以再次隐藏它。