android中TextView属性之autoText解析

本篇主要介绍TextView属性autoText。

如果没有时间看完全篇的同学们,可以直接看文章的最后第四点总结的内容。

一、看看android官方文档的描述。

在这之前,需要说明一点autoText虽然是TextView的属性之一,但它实际是服务于EditText。EditText是TextView的子类。

如果在TextView中设置属性autoText,编译器会提示“TextView不建议使用autoText属性”---因为设置了也是无效的。


二、那autoText在EditText中到底在干什么呢。来看看android TextView源码片段。

//autotext对应的是android:autotext属性
//autocap对应的是android:capitalize属性
if (autotext || autocap != -1) {
            TextKeyListener.Capitalize cap;

            inputType = EditorInfo.TYPE_CLASS_TEXT;

            switch (autocap) {
            case 1:
                cap = TextKeyListener.Capitalize.SENTENCES;//每句的第一个单词首字母转为大写
		//inputType对应的是android:inputType属性
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;//每一句的第一个单词的首字母大写
                break;

            case 2:
                cap = TextKeyListener.Capitalize.WORDS;//每个单词的首字母大写
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
                break;

            case 3:
                cap = TextKeyListener.Capitalize.CHARACTERS;//所有字符大写
                inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS;
                break;

            default:
                cap = TextKeyListener.Capitalize.NONE;
                break;
            }

            createEditorIfNeeded();
            mEditor.mKeyListener = TextKeyListener.getInstance(autotext, cap);
            mEditor.mInputType = inputType;
        }

此段源码中可以发现,其实就是给inputType这个属性赋值。

第31行中,再次把autoText传递给了TextKeyListener。看看TextKeyListener的源码:

public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
    private static TextKeyListener[] sInstance =
        new TextKeyListener[Capitalize.values().length * 2];

    /* package */ static final Object ACTIVE = new NoCopySpan.Concrete();
    /* package */ static final Object CAPPED = new NoCopySpan.Concrete();
    /* package */ static final Object INHIBIT_REPLACEMENT = new NoCopySpan.Concrete();
    /* package */ static final Object LAST_TYPED = new NoCopySpan.Concrete();

    private Capitalize mAutoCap;
    private boolean mAutoText;

    private int mPrefs;
    private boolean mPrefsInited;

    /* package */ static final int AUTO_CAP = 1;
    /* package */ static final int AUTO_TEXT = 2;
    /* package */ static final int AUTO_PERIOD = 4;
    /* package */ static final int SHOW_PASSWORD = 8;
    private WeakReference<ContentResolver> mResolver;
    private TextKeyListener.SettingsObserver mObserver;

    /**
     * Creates a new TextKeyListener with the specified capitalization
     * and correction properties.
     *
     * @param cap when, if ever, to automatically capitalize.
     * @param autotext whether to automatically do spelling corrections.
     */
    public TextKeyListener(Capitalize cap, boolean autotext) {
        mAutoCap = cap;
        mAutoText = autotext;
    }

    /**
     * Returns a new or existing instance with the specified capitalization
     * and correction properties.
     *
     * @param cap when, if ever, to automatically capitalize.
     * @param autotext whether to automatically do spelling corrections.
     */
    public static TextKeyListener getInstance(boolean autotext,
                                              Capitalize cap) {
        int off = cap.ordinal() * 2 + (autotext ? 1 : 0);

        if (sInstance[off] == null) {
            sInstance[off] = new TextKeyListener(cap, autotext);
        }

        return sInstance[off];
    }

    /**
     * Returns a new or existing instance with no automatic capitalization
     * or correction.
     */
    public static TextKeyListener getInstance() {
        return getInstance(false, Capitalize.NONE);
    }

    /**
     * Returns whether it makes sense to automatically capitalize at the
     * specified position in the specified text, with the specified rules.
     *
     * @param cap the capitalization rules to consider.
     * @param cs the text in which an insertion is being made.
     * @param off the offset into that text where the insertion is being made.
     *
     * @return whether the character being inserted should be capitalized.
     */
    public static boolean shouldCap(Capitalize cap, CharSequence cs, int off) {
        int i;
        char c;

        if (cap == Capitalize.NONE) {
            return false;
        }
        if (cap == Capitalize.CHARACTERS) {
            return true;
        }

        return TextUtils.getCapsMode(cs, off, cap == Capitalize.WORDS
                ? TextUtils.CAP_MODE_WORDS : TextUtils.CAP_MODE_SENTENCES)
                != 0;
    }

    public int getInputType() {
        return makeTextContentType(mAutoCap, mAutoText);
    }
    
    @Override
    public boolean onKeyDown(View view, Editable content,
                             int keyCode, KeyEvent event) {
        KeyListener im = getKeyListener(event);

        return im.onKeyDown(view, content, keyCode, event);
    }

    @Override
    public boolean onKeyUp(View view, Editable content,
                           int keyCode, KeyEvent event) {
        KeyListener im = getKeyListener(event);

        return im.onKeyUp(view, content, keyCode, event);
    }

    @Override
    public boolean onKeyOther(View view, Editable content, KeyEvent event) {
        KeyListener im = getKeyListener(event);

        return im.onKeyOther(view, content, event);
    }

    /**
     * Clear all the input state (autotext, autocap, multitap, undo)
     * from the specified Editable, going beyond Editable.clear(), which
     * just clears the text but not the input state.
     *
     * @param e the buffer whose text and state are to be cleared.
     */
    public static void clear(Editable e) {
        e.clear();
        e.removeSpan(ACTIVE);
        e.removeSpan(CAPPED);
        e.removeSpan(INHIBIT_REPLACEMENT);
        e.removeSpan(LAST_TYPED);

        QwertyKeyListener.Replaced[] repl = e.getSpans(0, e.length(),
                                   QwertyKeyListener.Replaced.class);
        final int count = repl.length;
        for (int i = 0; i < count; i++) {
            e.removeSpan(repl[i]);
        }
    }

    public void onSpanAdded(Spannable s, Object what, int start, int end) { }
    public void onSpanRemoved(Spannable s, Object what, int start, int end) { }

    public void onSpanChanged(Spannable s, Object what, int start, int end,
                              int st, int en) {
        if (what == Selection.SELECTION_END) {
            s.removeSpan(ACTIVE);
        }
    }

    private KeyListener getKeyListener(KeyEvent event) {
        KeyCharacterMap kmap = event.getKeyCharacterMap();
        int kind = kmap.getKeyboardType();

        if (kind == KeyCharacterMap.ALPHA) {
            return QwertyKeyListener.getInstance(mAutoText, mAutoCap);
        } else if (kind == KeyCharacterMap.NUMERIC) {
            return MultiTapKeyListener.getInstance(mAutoText, mAutoCap);
        } else if (kind == KeyCharacterMap.FULL
                || kind == KeyCharacterMap.SPECIAL_FUNCTION) {
            // We consider special function keyboards full keyboards as a workaround for
            // devices that do not have built-in keyboards.  Applications may try to inject
            // key events using the built-in keyboard device id which may be configured as
            // a special function keyboard using a default key map.  Ideally, as of Honeycomb,
            // these applications should be modified to use KeyCharacterMap.VIRTUAL_KEYBOARD.
            return QwertyKeyListener.getInstanceForFullKeyboard();
        }

        return NullKeyListener.getInstance();
    }

    public enum Capitalize {
        NONE, SENTENCES, WORDS, CHARACTERS,
    }

    private static class NullKeyListener implements KeyListener
    {
        public int getInputType() {
            return InputType.TYPE_NULL;
        }
        
        public boolean onKeyDown(View view, Editable content,
                                 int keyCode, KeyEvent event) {
            return false;
        }

        public boolean onKeyUp(View view, Editable content, int keyCode,
                                        KeyEvent event) {
            return false;
        }

        public boolean onKeyOther(View view, Editable content, KeyEvent event) {
            return false;
        }

        public void clearMetaKeyState(View view, Editable content, int states) {
        }
        
        public static NullKeyListener getInstance() {
            if (sInstance != null)
                return sInstance;

            sInstance = new NullKeyListener();
            return sInstance;
        }

        private static NullKeyListener sInstance;
    }

    public void release() {
        if (mResolver != null) {
            final ContentResolver contentResolver = mResolver.get();
            if (contentResolver != null) {
                contentResolver.unregisterContentObserver(mObserver);
                mResolver.clear();
            }
            mObserver = null;
            mResolver = null;
            mPrefsInited = false;
        }
    }

    private void initPrefs(Context context) {
        final ContentResolver contentResolver = context.getContentResolver();
        mResolver = new WeakReference<ContentResolver>(contentResolver);
        if (mObserver == null) {
            mObserver = new SettingsObserver();
            contentResolver.registerContentObserver(Settings.System.CONTENT_URI, true, mObserver);
        }

        updatePrefs(contentResolver);
        mPrefsInited = true;
    }

    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;
            }
        }
    }

    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);
    }

    /* package */ int getPrefs(Context context) {
        synchronized (this) {
            if (!mPrefsInited || mResolver.get() == null) {
                initPrefs(context);
            }
        }

        return mPrefs;
    }

以上源码中真正使用到autoText的是getInputType()这个方法。在看此方法调用的是makeTextContentType(mAutoCap, mAutoText),这个方法中其实还是在进行inputType的赋值。


三、看到这里,发现autoText和capitalize属性如影随形。而且感觉autoText没有什么用,真正跟autoText有关系的就是下面这句

if (autoText) {
            contentType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;//自动更正文本输入
        }

官方描述为“自动更正文本输入”。既然是更正,所以必须要有规则。没有规则就不知道什么是正确的。所以单独使用autoText是不起任何作用的。需要和capitalize配合使用。


四、最后,总结一下。

1、autoText是作用在EditText上的属性。

2、即使autoText和capitalize配合使用,他们也是在给inputType赋值。那我们为什么不直接使用inputType这个属性呢-----其实android官方也是建议直接使用inputType这个属性的。不管是使用autoText和capitalize或者inputType,其实只是对手机输入法软键盘有一些影响。EditText本身不会对setText的内容做什么调整。

如果你还是在使用autoText和capitalize这2个属性,最好使用inputType替换。不然出现如下警告:

Deprecated views, attributes and so on are deprecated because there is a better way to do something. Do it that new way. You've been warned

通过警告也可以看到,autoText和capitalize已经过时了。



去记录一个过时的方法,感觉有点“然而这并没有什么卵用”的感觉。只是自己在看到这个属性时,不知道这个属性在干什么。所以当我弄明白的时候,就记录于此。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨景文Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值