问题
There is a password visibility toggle button within TextInputLayout for InputType textPassword.
Is it somehow possible to catch toggle events?
I couldn't find any public methods for this
回答1:
I looked at the source code of the TextInputLayout to find the type of the view of the toggle button. Its CheckableImageButton. Everything else is easy. You need to find the view iterating recursively over children of the TextInputLayout View. And then setOnTouchListener as @MikeM suggested in the comments.
View togglePasswordButton = findTogglePasswordButton(mTextInputLayoutView);
if (togglePasswordButton != null) {
togglePasswordButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// implementation
return false;
}
});
}
private View findTogglePasswordButton(ViewGroup viewGroup) {
int childCount = viewGroup.getChildCount();
for (int ind = 0; ind < childCount; ind++) {
View child = viewGroup.getChildAt(ind);
if (child instanceof ViewGroup) {
View togglePasswordButton = findTogglePasswordButton((ViewGroup) child);
if (togglePasswordButton != null) {
return togglePasswordButton;
}
} else if (child instanceof CheckableImageButton) {
return child;
}
}
return null;
}
An alternative implmentation of findTogglePasswordButton
private View findTogglePasswordButton() {
return findViewById(R.id.text_input_password_toggle);
}
@MikeM. thank you for id
回答2:
You can use this:
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.design.widget.CheckableImageButton;
import android.support.design.widget.TextInputLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.ctm.core.ui.R;
import org.jetbrains.annotations.NotNull;
/**
* Extended {@link TextInputLayout} allowing setting a listener when the user toggles the visibility
* of the password.
*/
public class TextInputLayoutEx extends TextInputLayout {
public TextInputLayoutEx(Context context) {
super(context);
}
public TextInputLayoutEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextInputLayoutEx(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnToggleShowPasswordListener(OnToggleShowPasswordListener listener) {
if (listener != null) {
initTogglePasswordShownListener(listener);
}
}
@SuppressLint({"RestrictedApi"})
private void initTogglePasswordShownListener(@NotNull OnToggleShowPasswordListener listener) {
final View revealPasswordView = this.findViewById(R.id.text_input_password_toggle);
if (revealPasswordView == null) {
return;
}
if (!(revealPasswordView instanceof CheckableImageButton)) {
return;
}
final CheckableImageButton revealPasswordCheckableImageButton = (CheckableImageButton) revealPasswordView;
revealPasswordView.setOnTouchListener((view, motionEvent) -> {
if (MotionEvent.ACTION_UP == motionEvent.getAction()) {
listener.onToggleShowPasswordClicked(!revealPasswordCheckableImageButton.isChecked());
return view.performClick();
}
return false;
});
}
public interface OnToggleShowPasswordListener {
void onToggleShowPasswordClicked(boolean isShown);
}
}
In client code:
TextInputLayoutEx layoutPassword = (TextInputLayoutEx) findByById(...)
layoutPassword.setPasswordVisibilityToggleEnabled(true);
layoutPassword.setOnToggleShowPasswordListener(isShown -> Toast.makeText(SignInActivity.this, "Password shown: " + isShown, Toast.LENGTH_SHORT).show());
回答3:
After analyzing the View hierarchy with Layout Inspector I can see the following:
So you can either do:
val toggle = password.findViewById<CheckableImageButton?>(R.id.text_input_password_toggle)
toggle?.setOnClickListener {
println("clicked on toggle")
}
or manually:
// Assuming you have AndroidKTX
val views = password.children
for (v in views) {
if (v is FrameLayout) {
val innerViews = v.children
for (iv in innerViews) {
if (iv is CheckableImageButton) {
iv.setOnClickListener {
println("clicked on toggle")
}
}
}
}
}
回答4:
I'm using binding here.
This is the id of the layout - regPasswordlayout default id of the password toggle - text_input_password_toggle
binding.regPasswordlayout.findViewById(R.id.text_input_password_toggle)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// your code goes here
}
});
来源:https://stackoverflow.com/questions/45585854/android-textinputlayout-toggle-password-visibility-event-listener