1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
| private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
mTextSetFromXmlOrResourceId = false;
if (text == null) {
text = "";
}
// 移除SuggestionSpan,类似Word中拼写检查
// If suggestions are not enabled, remove the suggestion spans from the text
if (!isSuggestionsEnabled()) {
text = removeSuggestionSpans(text);
}
if (!mUserSetTextScaleX) mTextPaint.setTextScaleX(1.0f);
// 跑马灯效果
if (text instanceof Spanned
&& ((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) {
if (ViewConfiguration.get(mContext).isFadingMarqueeEnabled()) {
setHorizontalFadingEdgeEnabled(true);
mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
} else {
setHorizontalFadingEdgeEnabled(false);
mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
}
setEllipsize(TextUtils.TruncateAt.MARQUEE);
}
// 按照mFilters过滤文字
int n = mFilters.length;
for (int i = 0; i < n; i++) {
CharSequence out = mFilters[i].filter(text, 0, text.length(), EMPTY_SPANNED, 0, 0);
if (out != null) {
text = out;
}
}
// 方法中第三个参数起作用
if (notifyBefore) {
if (mText != null) {
oldlen = mText.length();
sendBeforeTextChanged(mText, 0, oldlen, text.length());
} else {
sendBeforeTextChanged("", 0, 0, text.length());
}
}
boolean needEditableForNotification = false;
if (mListeners != null && mListeners.size() != 0) {
needEditableForNotification = true;
}
// TextView文字排版相关
PrecomputedText precomputed =
(text instanceof PrecomputedText) ? (PrecomputedText) text : null;
// 可以编辑的内容重置状态,deep copy,最重要的是初始化Editor,后面用到。
if (type == BufferType.EDITABLE || getKeyListener() != null
|| needEditableForNotification) {
createEditorIfNeeded();
mEditor.forgetUndoRedo();
mEditor.scheduleRestartInputForSetText();
Editable t = mEditableFactory.newEditable(text);
text = t;
setFilters(t, mFilters);
} else if (precomputed != null) {
if (mTextDir == null) {
mTextDir = getTextDirectionHeuristic();
}
final boolean autoPhraseBreaking =
!mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
throw new IllegalArgumentException(
"PrecomputedText's Parameters don't match the parameters of this TextView."
+ "Consider using setTextMetricsParams(precomputedText.getParams()) "
+ "to override the settings of this TextView: "
+ "PrecomputedText: " + precomputed.getParams()
+ "TextView: " + getTextMetricsParams());
case PrecomputedText.Params.NEED_RECOMPUTE:
precomputed = PrecomputedText.create(precomputed, getTextMetricsParams());
break;
case PrecomputedText.Params.USABLE:
// pass through
}
} else if (type == BufferType.SPANNABLE || mMovement != null) {
// SPANNABLE deep copy
text = mSpannableFactory.newSpannable(text);
} else if (!(text instanceof CharWrapper)) {
text = TextUtils.stringOrSpannedString(text);
}
@AccessibilityUtils.A11yTextChangeType int a11yTextChangeType = AccessibilityUtils.NONE;
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
a11yTextChangeType = AccessibilityUtils.textOrSpanChanged(text, mText);
}
// 设置autolink更新type
if (mAutoLinkMask != 0) {
Spannable s2;
if (type == BufferType.EDITABLE || text instanceof Spannable) {
s2 = (Spannable) text;
} else {
s2 = mSpannableFactory.newSpannable(text);
}
if (Linkify.addLinks(s2, mAutoLinkMask)) {
text = s2;
type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
/*
* We must go ahead and set the text before changing the
* movement method, because setMovementMethod() may call
* setText() again to try to upgrade the buffer type.
*/
setTextInternal(text);
if (a11yTextChangeType == AccessibilityUtils.NONE) {
a11yTextChangeType = AccessibilityUtils.PARCELABLE_SPAN;
}
// Do not change the movement method for text that support text selection as it
// would prevent an arbitrary cursor displacement.
if (mLinksClickable && !textCanBeSelected()) {
setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
// 更新BufferType
mBufferType = type;
// 更新文字
setTextInternal(text);
// 像是把密码替换成*的文字处理类
if (mTransformation == null) {
mTransformed = text;
} else {
mTransformed = mTransformation.getTransformation(text, this);
}
if (mTransformed == null) {
// Should not happen if the transformation method follows the non-null postcondition.
mTransformed = "";
}
final int textLength = text.length();
final boolean isOffsetMapping = mTransformed instanceof OffsetMapping;
// !!!更新Span
if (text instanceof Spannable && (!mAllowTransformationLengthChange || isOffsetMapping)) {
Spannable sp = (Spannable) text;
// Remove any ChangeWatchers that might have come from other TextViews.
final ChangeWatcher[] watchers = sp.getSpans(0, sp.length(), ChangeWatcher.class);
final int count = watchers.length;
for (int i = 0; i < count; i++) {
sp.removeSpan(watchers[i]);
}
if (mChangeWatcher == null) mChangeWatcher = new ChangeWatcher();
sp.setSpan(mChangeWatcher, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE
| (CHANGE_WATCHER_PRIORITY << Spanned.SPAN_PRIORITY_SHIFT));
if (mEditor != null) mEditor.addSpanWatchers(sp);
if (mTransformation != null) {
final int priority = isOffsetMapping ? OFFSET_MAPPING_SPAN_PRIORITY : 0;
sp.setSpan(mTransformation, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE
| (priority << Spanned.SPAN_PRIORITY_SHIFT));
}
if (mMovement != null) {
mMovement.initialize(this, (Spannable) text);
/*
* Initializing the movement method will have set the
* selection, so reset mSelectionMoved to keep that from
* interfering with the normal on-focus selection-setting.
*/
if (mEditor != null) mEditor.mSelectionMoved = false;
}
}
if (mLayout != null) {
checkForRelayout();
}
sendOnTextChanged(text, 0, oldlen, textLength);
onTextChanged(text, 0, oldlen, textLength);
mHideHint = false;
if (a11yTextChangeType == AccessibilityUtils.TEXT) {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT);
} else if (a11yTextChangeType == AccessibilityUtils.PARCELABLE_SPAN) {
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
} else {
notifyListeningManagersAfterTextChanged();
}
if (mEditor != null) {
// SelectionModifierCursorController depends on textCanBeSelected, which depends on text
mEditor.prepareCursorControllers();
mEditor.maybeFireScheduledRestartInputForSetText();
}
}
|