本篇主要介绍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已经过时了。
去记录一个过时的方法,感觉有点“然而这并没有什么卵用”的感觉。只是自己在看到这个属性时,不知道这个属性在干什么。所以当我弄明白的时候,就记录于此。