android EditText 实现小写转大写源码分析

需求

输入框输入小写字母自动转为大写字母
android EditText 小写转大写实现分析
上面是个EditText 作为输入框。最下方view 记录的是原始输入内容。

实现


1.获取 android.text.method.ReplacementTransformationMethod 类的实例对象

    private ReplacementTransformationMethod transformationMethod = new ReplacementTransformationMethod() {
        @Override
        protected char[] getOriginal() {
            return new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
        }

        @Override
        protected char[] getReplacement() {
            return new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
        }
    };

2.为EditText添加 TransformationMethod 监听

editText.setTransformationMethod(transformationMethod);

注意:使用这种方法两个问题

  1. 通过 editText.getText().toString() 获取到的是用户操作的原始输入,不是转换后的。
  2. 在添加的 TextWatcher 监听中,同样获取到的是输入的原始值。

原理分析


android.text.method.ReplacementTransformationMethod

/**
 * 该类会将{@link #getOriginal}中的字符数组替换为{@link #getReplacement}数组。
 */
public abstract class ReplacementTransformationMethod
implements TransformationMethod
{
    /**
     * 返回显示时将被其他字符替换的字符列表。
     */
    protected abstract char[] getOriginal();
    /**
     * 返回替换的字符列表
     */
    protected abstract char[] getReplacement();

    /**
     * 处理替换的逻辑,getOriginal() 和  getReplacement() 方法在此方法内被调用以完成字符替换
     */
    public CharSequence getTransformation(CharSequence source, View v) {
    	...省略...
    }
 }

android.text.method.TransformationMethod

/**
 * TextView使用TransformationMethods进行字符替换操作,例如用点替换密码字符,或防止换行符在单行文本字段中引起换行。
 */
public interface TransformationMethod
{
    /**
     * 返回源文本sourceText转换后的数据。例如,用密码字段中的点替换每个字符。 需要主要的是返回的文本
     * 必须与源文本长度完全相同,并且如果源文本是可编辑的,则返回的文本必须动态镜像它,而不是进行一次复制。
     */
    public CharSequence getTransformation(CharSequence source, View view);

    /**
     * 使用该 TransformationMethod 的TextView 在获得/失去 焦点时调用
     */
    public void onFocusChanged(View view, CharSequence sourceText,
                               boolean focused, int direction,
                               Rect previouslyFocusedRect);
}

android.widget.TextView#setTransformationMethod

TextView 内部有两个字段来控制源文本和变换后的文本

    @ViewDebug.ExportedProperty(category = "text")
    private @Nullable CharSequence mText; //源文本
    private CharSequence mTransformed; //变换的文本

TextView 的setTransformationMethod 内部会调用 setText(java.lang.CharSequence) 方法,最终会执行到 setText(java.lang.CharSequence, android.widget.TextView.BufferType, boolean, int) 方法内。在该方法内调用 mTransformation.getTransformation(text, this) 方法对源数据进行变换,并把返回的值赋给 mTransformed 字段。

    private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen) {
    	...省略其他代码
    	
    	if (mTransformation == null) {
            mTransformed = text;
        } else {
            mTransformed = mTransformation.getTransformation(text, this);
        }

		... 省略其他代码
		sendOnTextChanged(text, 0, oldlen, textLength);
		... 省略其他代码
		sendAfterTextChanged((Editable) text);
		... 省略其他代码
    }

在 sendOnTextChanged 和 sendAfterTextChanged 方法中会执行文本改变监听的调用,而传入的text 为 mText ,非mTransformed,这也就解释了为啥在给TextView 添加 TextWatcher 监听时,获得的值仍然为源文本,而非转换后的文本

   /**
     * Not private so it can be called from an inner class without going
     * through a thunk.
     */
    void sendOnTextChanged(CharSequence text, int start, int before, int after) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).onTextChanged(text, start, before, after);
            }
        }

        if (mEditor != null) mEditor.sendOnTextChanged(start, before, after);
    }

    /**
     * Not private so it can be called from an inner class without going
     * through a thunk.
     */
    void sendAfterTextChanged(Editable text) {
        if (mListeners != null) {
            final ArrayList<TextWatcher> list = mListeners;
            final int count = list.size();
            for (int i = 0; i < count; i++) {
                list.get(i).afterTextChanged(text);
            }
        }

        // Always notify AutoFillManager - it will return right away if autofill is disabled.
        notifyAutoFillManagerAfterTextChangedIfNeeded();

        hideErrorIfUnchanged();
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值