Java tutorial
/* * Copyright (c) 2016, prchance, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by PRCHANCE. * */ package com.iutiao.sdk.views; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.DrawableRes; import android.support.v4.content.ContextCompat; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.inputmethod.EditorInfo; import com.iutiao.sdk.R; public class PasswordEditText extends AppCompatEditText { private static final String TAG = "DEBUG-WCL: " + PasswordEditText.class.getSimpleName(); // ? @DrawableRes private int mShowPwdIcon = R.drawable.iutiao_pwdet_visibility; // ? @DrawableRes private int mHidePwdIcon = R.drawable.iutiao_pwdet_visibility_off; private boolean mIsShowPwdIcon; // ? private Drawable mDrawableSide; // ?? public PasswordEditText(Context context) { this(context, null); } public PasswordEditText(Context context, AttributeSet attrs) { super(context, attrs); initFields(attrs, 0); } @TargetApi(21) public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initFields(attrs, defStyleAttr); } // ? public void initFields(AttributeSet attrs, int defStyleAttr) { if (attrs != null) { // ?? TypedArray styles = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordEditText, defStyleAttr, 0); try { // ??, Icon mShowPwdIcon = styles.getResourceId(R.styleable.PasswordEditText_pet_iconShow, mShowPwdIcon); mHidePwdIcon = styles.getResourceId(R.styleable.PasswordEditText_pet_iconHide, mHidePwdIcon); } finally { styles.recycle(); } } // ?? setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); 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) { if (s.length() > 0) { // showPasswordVisibilityIndicator(true); } else { mIsShowPwdIcon = false; restorePasswordIconVisibility(mIsShowPwdIcon); showPasswordVisibilityIndicator(false); // ?? } } @Override public void afterTextChanged(Editable s) { } }); } // ? @Override public Parcelable onSaveInstanceState() { Parcelable state = super.onSaveInstanceState(); return new PwdSavedState(state, mIsShowPwdIcon); } // ??? @Override public void onRestoreInstanceState(Parcelable state) { PwdSavedState savedState = (PwdSavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); mIsShowPwdIcon = savedState.isShowingIcon(); restorePasswordIconVisibility(mIsShowPwdIcon); } @Override public boolean onTouchEvent(MotionEvent event) { if (mDrawableSide == null) { return super.onTouchEvent(event); } final Rect bounds = mDrawableSide.getBounds(); final int x = (int) event.getRawX(); // ? int iconX = (int) getTopRightCorner().x; // Icon? int leftIcon = iconX - bounds.width(); Log.e(TAG, "x: " + x + ", leftIcon: " + leftIcon); // Icon?, ?? if (x >= leftIcon) { togglePasswordIconVisibility(); // ??? event.setAction(MotionEvent.ACTION_CANCEL); return false; } return super.onTouchEvent(event); } // ??? public PointF getTopRightCorner() { float src[] = new float[8]; float[] dst = new float[] { 0, 0, getWidth(), 0, 0, getHeight(), getWidth(), getHeight() }; getMatrix().mapPoints(src, dst); return new PointF(getX() + src[2], getY() + src[3]); } // ??? private void showPasswordVisibilityIndicator(boolean shouldShowIcon) { if (shouldShowIcon) { Drawable drawable = mIsShowPwdIcon ? ContextCompat.getDrawable(getContext(), mHidePwdIcon) : ContextCompat.getDrawable(getContext(), mShowPwdIcon); // ?? setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); mDrawableSide = drawable; } else { // ?? setCompoundDrawables(null, null, null, null); mDrawableSide = null; } } // ??? private void togglePasswordIconVisibility() { mIsShowPwdIcon = !mIsShowPwdIcon; restorePasswordIconVisibility(mIsShowPwdIcon); showPasswordVisibilityIndicator(true); } // ?? private void restorePasswordIconVisibility(boolean isShowPwd) { if (isShowPwd) { // ?? setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); } else { // ???? setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); } // setSelection(getText().length()); } // ??, Icon? protected static class PwdSavedState extends BaseSavedState { private final boolean mShowingIcon; private PwdSavedState(Parcelable superState, boolean showingIcon) { super(superState); mShowingIcon = showingIcon; } private PwdSavedState(Parcel in) { super(in); mShowingIcon = in.readByte() != 0; } public boolean isShowingIcon() { return mShowingIcon; } @Override public void writeToParcel(Parcel destination, int flags) { super.writeToParcel(destination, flags); destination.writeByte((byte) (mShowingIcon ? 1 : 0)); } public static final Creator<PwdSavedState> CREATOR = new Creator<PwdSavedState>() { public PwdSavedState createFromParcel(Parcel in) { return new PwdSavedState(in); } public PwdSavedState[] newArray(int size) { return new PwdSavedState[size]; } }; } }