Android EditText密码延迟后用星号替换点

Android EditText密码延迟后用星号替换点,android,android-edittext,passwords,Android,Android Edittext,Passwords,当用户输入密码时,我必须用星号替换点,因此我创建了自定义的PasswordTransformationMethod: public class LockerPasswordTransformationMethod extends PasswordTransformationMethod { @Override public CharSequence getTransformation(CharSequence source, View view) { retur

当用户输入密码时,我必须用星号替换点,因此我创建了自定义的
PasswordTransformationMethod

public class LockerPasswordTransformationMethod extends PasswordTransformationMethod {

    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        return new PasswordCharSequence(source);
    }

    private class PasswordCharSequence implements CharSequence {
        private CharSequence mSource;
        public PasswordCharSequence(CharSequence source) {
            mSource = source;
        }
        public char charAt(int index) {
            return '*';
        }
        public int length() {
            return mSource.length();
        }
        public CharSequence subSequence(int start, int end) {
            return mSource.subSequence(start, end);
        }
    }
}
我的xml:

        <EditText
            android:id="@+id/indicator"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:inputType="textPassword"
            android:letterSpacing="1.2"
        />

不幸的是,它会将我的文本立即变成星星,但我想在短时间内显示最后一个字符(就像在普通的EditText中,
inputType
设置为
password
),然后将其变成星号。如何实现这一点?

在您的on-create方法中,请初始化编辑文本。然后创建一个自定义类来执行此操作

 EditText UPL =(EditText) findViewById(R.id.UserPasswordToLogin) ;
        UPL.setTransformationMethod(new AsteriskPasswordTransformationMethod());
然后创建一个新的java类AsteriskPasswordTransformationMethod

public class AsteriskPasswordTransformationMethod extends PasswordTransformationMethod {
    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        return new PasswordCharSequence(source);
    }

    private class PasswordCharSequence implements CharSequence {
        private CharSequence mSource;
        public PasswordCharSequence(CharSequence source) {
            mSource = source; // Store char sequence
        }
        public char charAt(int index) {
            return '*'; // This is the important part
        }
        public int length() {
            return mSource.length(); // Return default
        }
        public CharSequence subSequence(int start, int end) {
            return mSource.subSequence(start, end); // Return default
        }
    }
};

您可以使用这个自定义类。我对原始类做了两个更改

点值从“\u2022”更改为“\u002A” 然后替换此代码

int pref = TextKeyListener.getInstance().getPrefs(v.getContext());
        if ((pref & SHOW_PASSWORD) != 0) {
            if (count > 0) {
                removeVisibleSpans(sp);

                if (count == 1) {
                    sp.setSpan(new Visible(sp, this), start, start + count,
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
        }

这是海关关卡

import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.GetChars;
import android.text.NoCopySpan;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.TransformationMethod;
import android.text.style.UpdateLayout;
import android.view.View;

import java.lang.ref.WeakReference;

public class CustomPasswordTransformationMethod
        implements TransformationMethod, TextWatcher {
    /* package */ static final Object ACTIVE = new NoCopySpan.Concrete();
    /* package */ static final Object CAPPED = new NoCopySpan.Concrete();
    /* package */ static final int SHOW_PASSWORD = 8;
    private static CustomPasswordTransformationMethod sInstance;
    private static char DOT = '\u002A';

    public static CustomPasswordTransformationMethod getInstance() {
        if (sInstance != null)
            return sInstance;

        sInstance = new CustomPasswordTransformationMethod();
        return sInstance;
    }

    private static void removeVisibleSpans(Spannable sp) {
        Visible[] old = sp.getSpans(0, sp.length(), Visible.class);
        for (int i = 0; i < old.length; i++) {
            sp.removeSpan(old[i]);
        }
    }

    public CharSequence getTransformation(CharSequence source, View view) {
        if (source instanceof Spannable) {
            Spannable sp = (Spannable) source;

            /*
             * Remove any references to other views that may still be
             * attached.  This will happen when you flip the screen
             * while a password field is showing; there will still
             * be references to the old EditText in the text.
             */
            ViewReference[] vr = sp.getSpans(0, sp.length(),
                    ViewReference.class);
            for (int i = 0; i < vr.length; i++) {
                sp.removeSpan(vr[i]);
            }

            removeVisibleSpans(sp);

            sp.setSpan(new ViewReference(view), 0, 0,
                    Spannable.SPAN_POINT_POINT);
        }

        return new PasswordCharSequence(source);
    }

    public void beforeTextChanged(CharSequence s, int start,
                                  int count, int after) {
        // This callback isn't used.
    }

    public void onTextChanged(CharSequence s, int start,
                              int before, int count) {
        if (s instanceof Spannable) {
            Spannable sp = (Spannable) s;
            ViewReference[] vr = sp.getSpans(0, s.length(),
                    ViewReference.class);
            if (vr.length == 0) {
                return;
            }

            /*
             * There should generally only be one ViewReference in the text,
             * but make sure to look through all of them if necessary in case
             * something strange is going on.  (We might still end up with
             * multiple ViewReferences if someone moves text from one password
             * field to another.)
             */
            View v = null;
            for (int i = 0; v == null && i < vr.length; i++) {
                v = vr[i].get();
            }

            if (v == null) {
                return;
            }
            removeVisibleSpans(sp);
            LogUtil.d("data", "start" + start + " count" + count);
            sp.setSpan(new Visible(sp, this), start, start + count,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);


           /* int pref = TextKeyListener.getInstance().getPrefs(v.getContext());
            if ((pref & SHOW_PASSWORD) != 0) {
                if (count > 0) {
                    removeVisibleSpans(sp);

                    if (count == 1) {
                        sp.setSpan(new Visible(sp, this), start, start + count,
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                }
            }*/
        }
    }

    public void afterTextChanged(Editable s) {
        // This callback isn't used.
    }

    public void onFocusChanged(View view, CharSequence sourceText,
                               boolean focused, int direction,
                               Rect previouslyFocusedRect) {
        if (!focused) {
            if (sourceText instanceof Spannable) {
                Spannable sp = (Spannable) sourceText;

                removeVisibleSpans(sp);
            }
        }
    }

    private static class PasswordCharSequence
            implements CharSequence, GetChars {
        private CharSequence mSource;

        public PasswordCharSequence(CharSequence source) {
            mSource = source;
        }

        public int length() {
            return mSource.length();
        }

        public char charAt(int i) {
            if (mSource instanceof Spanned) {
                Spanned sp = (Spanned) mSource;

                int st = sp.getSpanStart(ACTIVE);
                int en = sp.getSpanEnd(ACTIVE);

                if (i >= st && i < en) {
                    return mSource.charAt(i);
                }

                Visible[] visible = sp.getSpans(0, sp.length(), Visible.class);

                for (int a = 0; a < visible.length; a++) {
                    if (sp.getSpanStart(visible[a].mTransformer) >= 0) {
                        st = sp.getSpanStart(visible[a]);
                        en = sp.getSpanEnd(visible[a]);

                        if (i >= st && i < en) {
                            return mSource.charAt(i);
                        }
                    }
                }
            }

            return DOT;
        }

        public CharSequence subSequence(int start, int end) {
            char[] buf = new char[end - start];

            getChars(start, end, buf, 0);
            return new String(buf);
        }

        public String toString() {
            return subSequence(0, length()).toString();
        }

        public void getChars(int start, int end, char[] dest, int off) {
            TextUtils.getChars(mSource, start, end, dest, off);

            int st = -1, en = -1;
            int nvisible = 0;
            int[] starts = null, ends = null;

            if (mSource instanceof Spanned) {
                Spanned sp = (Spanned) mSource;

                st = sp.getSpanStart(ACTIVE);
                en = sp.getSpanEnd(ACTIVE);

                Visible[] visible = sp.getSpans(0, sp.length(), Visible.class);
                nvisible = visible.length;
                starts = new int[nvisible];
                ends = new int[nvisible];

                for (int i = 0; i < nvisible; i++) {
                    if (sp.getSpanStart(visible[i].mTransformer) >= 0) {
                        starts[i] = sp.getSpanStart(visible[i]);
                        ends[i] = sp.getSpanEnd(visible[i]);
                    }
                }
            }

            for (int i = start; i < end; i++) {
                if (!(i >= st && i < en)) {
                    boolean visible = false;

                    for (int a = 0; a < nvisible; a++) {
                        if (i >= starts[a] && i < ends[a]) {
                            visible = true;
                            break;
                        }
                    }

                    if (!visible) {
                        dest[i - start + off] = DOT;
                    }
                }
            }
        }
    }

    private static class Visible
            extends Handler
            implements UpdateLayout, Runnable {
        private Spannable mText;
        private CustomPasswordTransformationMethod mTransformer;

        public Visible(Spannable sp, CustomPasswordTransformationMethod ptm) {
            mText = sp;
            mTransformer = ptm;
            postAtTime(this, SystemClock.uptimeMillis() + 1000);
        }

        public void run() {
            mText.removeSpan(this);
        }
    }

    /**
     * Used to stash a reference back to the View in the Editable so we
     * can use it to check the settings.
     */
    private static class ViewReference extends WeakReference<View>
            implements NoCopySpan {
        public ViewReference(View v) {
            super(v);
        }
    }
}
导入android.graphics.Rect;
导入android.os.Handler;
导入android.os.SystemClock;
导入android.text.Editable;
导入android.text.GetChars;
导入android.text.NoCopySpan;
导入android.text.Spannable;
导入android.text.span;
导入android.text.TextUtils;
导入android.text.TextWatcher;
导入android.text.method.TransformationMethod;
导入android.text.style.UpdateLayout;
导入android.view.view;
导入java.lang.ref.WeakReference;
公共类CustomPasswordTransformationMethod
实现TransformationMethod,TextWatcher{
/*package*/static final Object ACTIVE=new NoCopySpan.Concrete();
/*package*/static final Object CAPPED=new NoCopySpan.Concrete();
/*包*/静态最终整数显示\密码=8;
私有静态CustomPasswordTransformationMethod站;
私有静态字符点='\u002A';
公共静态CustomPasswordTransformationMethod getInstance(){
if(sInstance!=null)
回归承诺;
sInstance=新的CustomPasswordTransformationMethod();
回归承诺;
}
专用静态void removeVisibleSpands(可扩展sp){
Visible[]old=sp.getSpans(0,sp.length(),Visible.class);
for(int i=0;i0){
移除可视跨度(sp);
如果(计数=1){
sp.setSpan(新可见(sp,此)、开始、开始+计数、,
Spannable.SPAN_独占性SPAN_独占性);
}
}
}*/
}
}
公共无效后文本已更改(可编辑){
//此回调未使用。
}
public void onFocusChanged(视图、字符序列、源文本、,
布尔聚焦,整数方向,
直肠前病灶(直肠){
如果(!聚焦){
if(sourceText instanceof Spannable){
Spannable sp=(Spannable)源文本;
移除可视跨度(sp);
}
}
}
私有静态类PasswordCharSequence
实现CharSequence,GetChars{
私有字符源;
公共密码CharSequence(CharSequence源){
mSource=源;
}
公共整数长度(){
返回mSource.length();
}
公共字符(int i){
if(mSource instanceof span){
跨距sp=(跨距)mSource;
int st=sp.getSpanStart(激活);
int en=sp.getSpanEnd(激活);
如果(i>=st&&i removeVisibleSpans(sp);
sp.setSpan(new Visible(sp, this), start, start + count,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.GetChars;
import android.text.NoCopySpan;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.TransformationMethod;
import android.text.style.UpdateLayout;
import android.view.View;

import java.lang.ref.WeakReference;

public class CustomPasswordTransformationMethod
        implements TransformationMethod, TextWatcher {
    /* package */ static final Object ACTIVE = new NoCopySpan.Concrete();
    /* package */ static final Object CAPPED = new NoCopySpan.Concrete();
    /* package */ static final int SHOW_PASSWORD = 8;
    private static CustomPasswordTransformationMethod sInstance;
    private static char DOT = '\u002A';

    public static CustomPasswordTransformationMethod getInstance() {
        if (sInstance != null)
            return sInstance;

        sInstance = new CustomPasswordTransformationMethod();
        return sInstance;
    }

    private static void removeVisibleSpans(Spannable sp) {
        Visible[] old = sp.getSpans(0, sp.length(), Visible.class);
        for (int i = 0; i < old.length; i++) {
            sp.removeSpan(old[i]);
        }
    }

    public CharSequence getTransformation(CharSequence source, View view) {
        if (source instanceof Spannable) {
            Spannable sp = (Spannable) source;

            /*
             * Remove any references to other views that may still be
             * attached.  This will happen when you flip the screen
             * while a password field is showing; there will still
             * be references to the old EditText in the text.
             */
            ViewReference[] vr = sp.getSpans(0, sp.length(),
                    ViewReference.class);
            for (int i = 0; i < vr.length; i++) {
                sp.removeSpan(vr[i]);
            }

            removeVisibleSpans(sp);

            sp.setSpan(new ViewReference(view), 0, 0,
                    Spannable.SPAN_POINT_POINT);
        }

        return new PasswordCharSequence(source);
    }

    public void beforeTextChanged(CharSequence s, int start,
                                  int count, int after) {
        // This callback isn't used.
    }

    public void onTextChanged(CharSequence s, int start,
                              int before, int count) {
        if (s instanceof Spannable) {
            Spannable sp = (Spannable) s;
            ViewReference[] vr = sp.getSpans(0, s.length(),
                    ViewReference.class);
            if (vr.length == 0) {
                return;
            }

            /*
             * There should generally only be one ViewReference in the text,
             * but make sure to look through all of them if necessary in case
             * something strange is going on.  (We might still end up with
             * multiple ViewReferences if someone moves text from one password
             * field to another.)
             */
            View v = null;
            for (int i = 0; v == null && i < vr.length; i++) {
                v = vr[i].get();
            }

            if (v == null) {
                return;
            }
            removeVisibleSpans(sp);
            LogUtil.d("data", "start" + start + " count" + count);
            sp.setSpan(new Visible(sp, this), start, start + count,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);


           /* int pref = TextKeyListener.getInstance().getPrefs(v.getContext());
            if ((pref & SHOW_PASSWORD) != 0) {
                if (count > 0) {
                    removeVisibleSpans(sp);

                    if (count == 1) {
                        sp.setSpan(new Visible(sp, this), start, start + count,
                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                }
            }*/
        }
    }

    public void afterTextChanged(Editable s) {
        // This callback isn't used.
    }

    public void onFocusChanged(View view, CharSequence sourceText,
                               boolean focused, int direction,
                               Rect previouslyFocusedRect) {
        if (!focused) {
            if (sourceText instanceof Spannable) {
                Spannable sp = (Spannable) sourceText;

                removeVisibleSpans(sp);
            }
        }
    }

    private static class PasswordCharSequence
            implements CharSequence, GetChars {
        private CharSequence mSource;

        public PasswordCharSequence(CharSequence source) {
            mSource = source;
        }

        public int length() {
            return mSource.length();
        }

        public char charAt(int i) {
            if (mSource instanceof Spanned) {
                Spanned sp = (Spanned) mSource;

                int st = sp.getSpanStart(ACTIVE);
                int en = sp.getSpanEnd(ACTIVE);

                if (i >= st && i < en) {
                    return mSource.charAt(i);
                }

                Visible[] visible = sp.getSpans(0, sp.length(), Visible.class);

                for (int a = 0; a < visible.length; a++) {
                    if (sp.getSpanStart(visible[a].mTransformer) >= 0) {
                        st = sp.getSpanStart(visible[a]);
                        en = sp.getSpanEnd(visible[a]);

                        if (i >= st && i < en) {
                            return mSource.charAt(i);
                        }
                    }
                }
            }

            return DOT;
        }

        public CharSequence subSequence(int start, int end) {
            char[] buf = new char[end - start];

            getChars(start, end, buf, 0);
            return new String(buf);
        }

        public String toString() {
            return subSequence(0, length()).toString();
        }

        public void getChars(int start, int end, char[] dest, int off) {
            TextUtils.getChars(mSource, start, end, dest, off);

            int st = -1, en = -1;
            int nvisible = 0;
            int[] starts = null, ends = null;

            if (mSource instanceof Spanned) {
                Spanned sp = (Spanned) mSource;

                st = sp.getSpanStart(ACTIVE);
                en = sp.getSpanEnd(ACTIVE);

                Visible[] visible = sp.getSpans(0, sp.length(), Visible.class);
                nvisible = visible.length;
                starts = new int[nvisible];
                ends = new int[nvisible];

                for (int i = 0; i < nvisible; i++) {
                    if (sp.getSpanStart(visible[i].mTransformer) >= 0) {
                        starts[i] = sp.getSpanStart(visible[i]);
                        ends[i] = sp.getSpanEnd(visible[i]);
                    }
                }
            }

            for (int i = start; i < end; i++) {
                if (!(i >= st && i < en)) {
                    boolean visible = false;

                    for (int a = 0; a < nvisible; a++) {
                        if (i >= starts[a] && i < ends[a]) {
                            visible = true;
                            break;
                        }
                    }

                    if (!visible) {
                        dest[i - start + off] = DOT;
                    }
                }
            }
        }
    }

    private static class Visible
            extends Handler
            implements UpdateLayout, Runnable {
        private Spannable mText;
        private CustomPasswordTransformationMethod mTransformer;

        public Visible(Spannable sp, CustomPasswordTransformationMethod ptm) {
            mText = sp;
            mTransformer = ptm;
            postAtTime(this, SystemClock.uptimeMillis() + 1000);
        }

        public void run() {
            mText.removeSpan(this);
        }
    }

    /**
     * Used to stash a reference back to the View in the Editable so we
     * can use it to check the settings.
     */
    private static class ViewReference extends WeakReference<View>
            implements NoCopySpan {
        public ViewReference(View v) {
            super(v);
        }
    }
}