Android Edittext密码类型显示字符串修改实现

Posted 峥嵘life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Edittext密码类型显示字符串修改实现相关的知识,希望对你有一定的参考价值。

android Edittext密码类型显示字符串修改实现

文章目录

一、前言:

Edittex 设置inputType 为密码类型passwordtext,当前输入的密码字符串会只短暂显示1秒左右,
某些情况,有些app为了把安全等级提供,会把Edittext默认设置成不短暂显示密码。

一般的情况,我们可能只会用到下面两个场景。


//默认模式显示小圆点和一瞬间
EditText.setTransformationMethod(new PasswordTransformationMethod()); //hide

//设置密码一直可见
EditText.setTransformationMethod(HideReturnsTransformationMethod.getInstance());//show

其他情况,虽然不多,但是多学习也是有好处的。

主要是找了网上不少文章,都没有看到对EditText进行一定研究的,
所以记录一下,这次学习的过程,给其他人做参考。

二、效果

功能图:


主要展示:


1、一个应用设置全局,系统级密码不可见,另外一个应用也生效了。
2、应用内设置密码可见/不可见
3、当个EditText 修改密码显示符号

看下效果:

显示优先级:当个>应用设置>系统设置
也就是说:
当个EditText修改了密码显示符号,无论应用设置和系统设置是什么,都只会显示修改后的符号;
当个EditText未修改密码显示符号,应用设置密码不可见,无论系统设置啥都不会可见;

这里的修改并不影响密码设置一直可见,再次设置密码可见还是有效的。

三、实现

本文从系统级,应用级,单个Edittext三个方面进行了实现。

对应系统级和应用级的实现都是需要系统签名的,而单个Edittext的实现是不用权限的。

1、系统级设置

设置之后,都整个系统默认的情况进行设置。

系统默认的密码输入框是短暂可见的。

//系统级:设置密码是否短暂可见
private void inSystemSetPasswordIsShortShow(boolean isChecked) 
	Log.i(TAG, "inSystemSetPasswordIsShortShow isChecked = " + isChecked);
	Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, isChecked ? 1 : 0);


需要权限:


<uses-permission android:name="android.permission.WRITE_SETTINGS" " />

2、应用级设置

设置之后,对当前应用有效。

 //应用级:设置密码是否短暂可见
    //设置密码是否显示一瞬间
    @SuppressLint("SoonBlockedPrivateApi")
    private void inAppSetPasswordShowMoment(boolean isShowPasswordMoment) 
        Log.i(TAG, "setPasswordShowMoment isShowPasswordMoment = " + isShowPasswordMoment);
        TextKeyListener textKeyListener = TextKeyListener.getInstance();
        Class<? extends TextKeyListener> fatherClass = textKeyListener.getClass();
        try 

            //必须调用一次getPrefs方法,执行属性设置
            Method getPrefs = fatherClass.getDeclaredMethod("getPrefs", Context.class);
            getPrefs.setAccessible(true);
            Object invoke = getPrefs.invoke(textKeyListener, this);
            Log.i(TAG, "invoke = " + invoke);

            // 获取类的私有字段 name
            Field name = fatherClass.getDeclaredField("mPrefs");
            // 设置为可以访问
            name.setAccessible(true);
            Object o = name.get(textKeyListener);
            Log.i(TAG, "o = " + o);
            int pre = Integer.parseInt("" + o);
            if (isShowPasswordMoment) 
                pre |= 8;
             else 
                pre &= ~8; //直接设置成0 ,就是不显示密码,但是会造成不可恢复
            

            // 修改实例father中的字段name
            name.set(textKeyListener, pre);
            o = name.get(textKeyListener);
            Log.i(TAG, pre + ", o = " + o);

         catch (Exception e) 
            Log.i(TAG, "errro = " + e);
        

        Log.i(TAG, "end");
    



3、单个EditText设置

下面是替换只对当个应用有效,并且可以设置替换加密符号。

网上也有一些自己写OnTextChange ,自己做显示的,但是我感觉下面的这种是目前最方便的。

(1)自定义显示符合类


import android.text.method.ReplacementTransformationMethod;

public class WordReplacement extends ReplacementTransformationMethod 

    char mShowChar = '.';

    public WordReplacement() 

    

    public WordReplacement(char showChar) 
        mShowChar = showChar;
    


    String strWord = null;

    @Override
    protected char[] getOriginal() 
        //循环ASCII值 字符串形式累加到String
        for (char i = 0; i < 256; i++) 
            strWord += String.valueOf(i);
        
        //strWord转换为字符形式的数组
        char[] charOriginal = strWord.toCharArray();
        return charOriginal;
    

    @Override
    protected char[] getReplacement() 
        char[] charReplacement = new char[255];
        //输入的字符在ASCII范围内,将其转换为*
        for (int i = 0; i < 255; i++) 
            charReplacement[i] = mShowChar;
        
        return charReplacement;
    



(2)EditText使用自定义密码显示符合即可。


//对当个Edittext设置密码字符串
private void curSetSetPasswordShowMoment(boolean isShowPasswordMoment) 
    if (isShowPasswordMoment) 
        et_mychange.setTransformationMethod(new PasswordTransformationMethod());//默认模式显示小圆点和一瞬间
     else 
        WordReplacement wordReplacement = new WordReplacement('*');//传入需要的字符串,只显示这个符号
        et_mychange.setTransformationMethod(wordReplacement);
    



3、源代码的一点分析研究

这里不做具体流程分析了,主要分析监听系统设置密码可见的逻辑和默认显示小圆点的逻辑的代码。

(1)监听 Settings.System.TEXT_SHOW_PASSWORD 属性值修改的代码

frameworks\\base\\core\\java\\android\\text\\method\\TextKeyListener.java


    //监听 Settings 属性变化
    private class SettingsObserver extends ContentObserver 
        public SettingsObserver() 
            super(new Handler());
        

        @Override
        public void onChange(boolean selfChange) 
            if (mResolver != null) 
                final ContentResolver contentResolver = mResolver.get();
                if (contentResolver == null) 
                    mPrefsInited = false;
                 else 
                    updatePrefs(contentResolver);
                
             else 
                mPrefsInited = false;
            
        
    


    //监听 System.TEXT_SHOW_PASSWORD 等属性变化
    //根据几个值决定是否显示密码字符串,最根本的还是 TEXT_SHOW_PASSWORD 这个属性
    private void updatePrefs(ContentResolver resolver) 
        boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) > 0;
        boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) > 0;
        boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) > 0;
        boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) > 0;

        mPrefs = (cap ? AUTO_CAP : 0) |
            (text ? AUTO_TEXT : 0) |
            (period ? AUTO_PERIOD : 0) |
            (pw ? SHOW_PASSWORD : 0);
        

    //获取密码显示状态
    int getPrefs(Context context) 
        synchronized (this) 
        if (!mPrefsInited || mResolver.get() == null) 
            initPrefs(context);
        
    

    return mPrefs;



(2)系统默认显示小圆点的代码

frameworks\\base\\core\\java\\android\\text\\method\\PasswordTransformationMethod.java




    //默认显示一瞬间封装对象,时间为1500毫秒,即1.5秒,这就是答案
    private static class Visible
    extends Handler
    implements UpdateLayout, Runnable
    
        public Visible(Spannable sp, PasswordTransformationMethod ptm) 
            mText = sp;
            mTransformer = ptm;
            postAtTime(this, SystemClock.uptimeMillis() + 1500);
        

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

        private Spannable mText;
        private PasswordTransformationMethod mTransformer;
    

    //EditText 输入的文本变化回调
    public void onTextChanged(CharSequence s, int start,
                              int before, int count) 
        if (s instanceof Spannable) 
。。。
            int pref = TextKeyListener.getInstance().getPrefs(v.getContext()); //判断密码的状态,再做显示处理
            if ((pref & TextKeyListener.SHOW_PASSWORD) != 0) 
                if (count > 0) 
                    removeVisibleSpans(sp);

                    if (count == 1) 
                    //每个字符都会创建一个显示瞬间的对象
                        sp.setSpan(new Visible(sp, this), start, start + count,
                                   Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    
                
            
        
    


    //每个字符替换成小圆点的逻辑,封装类
    private static class PasswordCharSequence
    implements CharSequence, GetChars
    
        public PasswordCharSequence(CharSequence source) 
            mSource = source;
        

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

        public char charAt(int i) 
            if (mSource instanceof Spanned) 
        。。。
                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;//小圆点
        


private static char DOT = '\\u2022'; //这个char字符,显示的就是小圆点符号


(3)关联

EditText 、TextKeyListener、PasswordTransformationMethod 是哪里关联上的呢?

① EditText 的子类TextView 中有判断是否显示密码的逻辑
     // isPassword 从 xml 获取是否密码类型的逻辑不详解了!
     if (isPassword) 
            setTransformationMethod(PasswordTransformationMethod.getInstance());
        

② PasswordTransformationMethod中的 onTextChanged方法对每个字符变化都判断当前密码模式进行显示

int pref = TextKeyListener.getInstance().getPrefs(v.getContext()); //判断密码的状态,再做显示处理

4、demo apk代码资源

https://download.csdn.net/download/wenzhi20102321/87256653

共勉:在奋斗中寻找乐趣,让单调的生活充满生机。

以上是关于Android Edittext密码类型显示字符串修改实现的主要内容,如果未能解决你的问题,请参考以下文章

(转)Android EditText限制输入字符的5种实现方式

android EditText密码框,怎么让它只显示密码点,不让它显示最后一位输入的字符?

Android 设置密码文本是否暂时显示字符

Android 设置密码文本是否暂时显示字符

android EditText 如何 才能默认弹出的键盘为数字键盘,同时又是显示成密码的小圆点

EditText限制输入的几种方式及只显示中文汉字的做法