带有 TextInputLayouts passwordToggleEnabled 的可见密码
Visible password with TextInputLayouts passwordToggleEnabled
我正在使用带有支持库中的新功能的 TextInputLayout:passwordToggleEnabled。这提供了一个漂亮的 "eye" 图标,允许用户打开和关闭密码可见性。
我的问题是是否有一种方法可以使用此功能但从密码可见开始?
我的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>
切换看起来类似于:
我在 xml 中没有找到执行此操作的方法,也没有在呈现视图后手动切换可见性的方法。如果我将 EditText 的输入类型设置为 textVisiblePassword,则不会显示切换。如果我在代码中使用 mPasswordEditText.setTransformationMethod(null);显示了密码,但切换消失了,用户无法再次隐藏密码。我知道我可以手动完成所有操作,但只是想知道我是否可以使用新的魔术切换
您可以使用:
yourEditText.setTransformationMethod(new PasswordTransformationMethod());
到re-show可读密码,只需要传递null作为转换方法:
yourEditText.setTransformationMethod(null);
所以用户可以再次隐藏它。
其中一种方法是,我们可以从 TextInputLayout
中搜索 CheckableImageButton
,然后根据 EditText
的密码可见性状态,以编程方式对其执行 onClick
.
这是代码片段。
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();
}
}
我能够使用以下代码让它以明文模式启动。基本上,我必须使用内容描述找到正确的视图。
如果他们为 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();
}
}
}
下面是最简单的方法 这个答案的最后是另一个解决方案
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
在查看 TextInputLayout.java
I found that, there is a layout design_text_input_password_icon.xml
which is being added to 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;
}
您可以使用以下代码:
TextInputLayout yourTextInputLayoutId = findViewById(R.id.yourTextInputLayoutId);
FrameLayout frameLayout = (FrameLayout) (yourTextInputLayoutId).getChildAt(0);
CheckableImageButton checkableImageButton = (CheckableImageButton) frameLayout.getChildAt(1);
checkableImageButton.performClick();
这里 yourTextInputLayoutId
是来自 xml 的 TextInputLayout id。
试试这个
if (inputEditText.getTransformationMethod() == null) {
inputEditText.setTransformationMethod(new PasswordTransformationMethod());
} else {
inputEditText.setTransformationMethod(null);
}
inputEditText.setSelection(inputEditText.getText().length());
要从密码可见开始,
不包括
android:inputType="textPassword"
在
<com.google.android.material.textfield.TextInputEditText>
....
</com.google.android.material.textfield.TextInputEditText>
使用 Material 组件库(1.1.0
、1.2.0-beta01
、1.3.0-alpha01
)以可见密码开始,只需使用:
<com.google.android.material.textfield.TextInputLayout
app:endIconMode="password_toggle"
/>
并在您的代码中:
textInputLayout.getEditText().setTransformationMethod(null);
如果您想 return 默认行为:
textInputLayout.getEditText()
.setTransformationMethod(PasswordTransformationMethod.getInstance());
只是删除 android:inputType="textPassword"
对我有用
我正在使用带有支持库中的新功能的 TextInputLayout:passwordToggleEnabled。这提供了一个漂亮的 "eye" 图标,允许用户打开和关闭密码可见性。
我的问题是是否有一种方法可以使用此功能但从密码可见开始?
我的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>
切换看起来类似于:
我在 xml 中没有找到执行此操作的方法,也没有在呈现视图后手动切换可见性的方法。如果我将 EditText 的输入类型设置为 textVisiblePassword,则不会显示切换。如果我在代码中使用 mPasswordEditText.setTransformationMethod(null);显示了密码,但切换消失了,用户无法再次隐藏密码。我知道我可以手动完成所有操作,但只是想知道我是否可以使用新的魔术切换
您可以使用:
yourEditText.setTransformationMethod(new PasswordTransformationMethod());
到re-show可读密码,只需要传递null作为转换方法:
yourEditText.setTransformationMethod(null);
所以用户可以再次隐藏它。
其中一种方法是,我们可以从 TextInputLayout
中搜索 CheckableImageButton
,然后根据 EditText
的密码可见性状态,以编程方式对其执行 onClick
.
这是代码片段。
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();
}
}
我能够使用以下代码让它以明文模式启动。基本上,我必须使用内容描述找到正确的视图。
如果他们为 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();
}
}
}
下面是最简单的方法 这个答案的最后是另一个解决方案
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
在查看 TextInputLayout.java
I found that, there is a layout design_text_input_password_icon.xml
which is being added to 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;
}
您可以使用以下代码:
TextInputLayout yourTextInputLayoutId = findViewById(R.id.yourTextInputLayoutId);
FrameLayout frameLayout = (FrameLayout) (yourTextInputLayoutId).getChildAt(0);
CheckableImageButton checkableImageButton = (CheckableImageButton) frameLayout.getChildAt(1);
checkableImageButton.performClick();
这里 yourTextInputLayoutId
是来自 xml 的 TextInputLayout id。
试试这个
if (inputEditText.getTransformationMethod() == null) {
inputEditText.setTransformationMethod(new PasswordTransformationMethod());
} else {
inputEditText.setTransformationMethod(null);
}
inputEditText.setSelection(inputEditText.getText().length());
要从密码可见开始, 不包括
android:inputType="textPassword"
在
<com.google.android.material.textfield.TextInputEditText>
....
</com.google.android.material.textfield.TextInputEditText>
使用 Material 组件库(1.1.0
、1.2.0-beta01
、1.3.0-alpha01
)以可见密码开始,只需使用:
<com.google.android.material.textfield.TextInputLayout
app:endIconMode="password_toggle"
/>
并在您的代码中:
textInputLayout.getEditText().setTransformationMethod(null);
如果您想 return 默认行为:
textInputLayout.getEditText()
.setTransformationMethod(PasswordTransformationMethod.getInstance());
只是删除 android:inputType="textPassword"
对我有用