下面列出了android.text.Editable#subSequence ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* The default implementation returns the text currently selected, or null if none is
* selected.
*/
public CharSequence getSelectedText(int flags) {
final Editable content = getEditable();
if (content == null) return null;
int a = Selection.getSelectionStart(content);
int b = Selection.getSelectionEnd(content);
if (a > b) {
int tmp = a;
a = b;
b = tmp;
}
if (a == b || a < 0) return null;
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
return content.subSequence(a, b);
}
return TextUtils.substring(content, a, b);
}
/**
* Instead of validating the entire text, this subclass method validates
* each token of the text individually. Empty tokens are removed.
*/
@Override
public void performValidation() {
Validator v = getValidator();
if (v == null || mTokenizer == null) {
return;
}
Editable e = getText();
int i = getText().length();
while (i > 0) {
int start = mTokenizer.findTokenStart(e, i);
int end = mTokenizer.findTokenEnd(e, start);
CharSequence sub = e.subSequence(start, end);
if (TextUtils.isEmpty(sub)) {
e.replace(start, i, "");
} else if (!v.isValid(sub)) {
e.replace(start, i,
mTokenizer.terminateToken(v.fixText(sub)));
}
i = start;
}
}
void createMoreChipPlainText()
{
// Take the first <= CHIP_LIMIT addresses and get to the end of the second one.
final Editable text=getText();
int start=0;
int end=start;
for(int i=0;i<CHIP_LIMIT;i++)
{
end=movePastTerminators(mTokenizer.findTokenEnd(text,start));
start=end; // move to the next token and get its end.
}
// Now, count total addresses.
start=0;
final int tokenCount=countTokens(text);
final MoreImageSpan moreSpan=createMoreSpan(tokenCount-CHIP_LIMIT);
final SpannableString chipText=new SpannableString(text.subSequence(end,text.length()));
chipText.setSpan(moreSpan,0,chipText.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(end,text.length(),chipText);
mMoreChip=moreSpan;
}
public void replaceEmoticons(Editable editable, int start, int count) {
if (count <= 0 || editable.length() < start + count)
return;
CharSequence s = editable.subSequence(start, start + count);
Matcher matcher = Pattern.compile("\\[[^\\[]+\\]").matcher(s);
while (matcher.find()) {
int from = start + matcher.start();
int to = start + matcher.end();
String emot = editable.subSequence(from, to).toString();
emot = emot.substring(1, emot.length() - 1) + ".png";
String key = StickerCategory.emojiMaps.get(emot);
if (!TextUtils.isEmpty(key)) {
emot = key;
}
Drawable d = ResourceUtil.getEmotDrawable(emot);
if (d != null) {
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
editable.setSpan(span, from, to, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
void createMoreChipPlainText() {
// Take the first <= CHIP_LIMIT addresses and get to the end of the second one.
Editable text = getText();
int start = 0;
int end = start;
for (int i = 0; i < CHIP_LIMIT; i++) {
end = movePastTerminators(mTokenizer.findTokenEnd(text, start));
start = end; // move to the next token and get its end.
}
// Now, count total addresses.
start = 0;
int tokenCount = countTokens(text);
MoreImageSpan moreSpan = createMoreSpan(tokenCount - CHIP_LIMIT);
SpannableString chipText = new SpannableString(text.subSequence(end, text.length()));
chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(end, text.length(), chipText);
mMoreChip = moreSpan;
}
public static void replaceEmoticons(Context context, Editable editable, int start, int count) {
if (count <= 0 || editable.length() < start + count)
return;
CharSequence s = editable.subSequence(start, start + count);
Matcher matcher = EmoUtil.getPattern().matcher(s);
while (matcher.find()) {
int from = start + matcher.start();
int to = start + matcher.end();
String emot = editable.subSequence(from, to).toString();
Drawable d = getEmotDrawable(context, emot, DEF_SCALE);
if (d != null) {
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
editable.setSpan(span, from, to, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
/**
* Mark text that was duplicated during text composition to delete it later.
*
* @param text the given text
* @param cursor the index of the cursor in text
* @param tokenizer the {@link Tokenizer} to use
*/
private void markDuplicatedTextForDeletionLater(@NonNull Editable text, int cursor, @NonNull Tokenizer tokenizer) {
while (cursor > 0 && tokenizer.isWordBreakingChar(text.charAt(cursor - 1))) {
cursor--;
}
int wordStart = findStartOfWord(text, cursor);
PlaceholderSpan[] placeholderSpans = text.getSpans(wordStart, wordStart + 1, PlaceholderSpan.class);
for (PlaceholderSpan span : placeholderSpans) {
int spanEnd = span.originalEnd;
int copyEnd = spanEnd + (spanEnd - wordStart);
if (copyEnd > spanEnd && copyEnd <= text.length()) {
CharSequence endOfMention = text.subSequence(wordStart, spanEnd);
CharSequence copyOfEndOfMentionText = text.subSequence(spanEnd, copyEnd);
// Note: Comparing strings since we do not want to compare any other aspects of spanned strings
if (endOfMention.toString().equals(copyOfEndOfMentionText.toString())) {
text.setSpan(new DeleteSpan(),
spanEnd,
copyEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
}
public static void replaceEmoticons(Context context, Editable editable, int start, int count) {
if (count <= 0 || editable.length() < start + count)
return;
CharSequence s = editable.subSequence(start, start + count);
Matcher matcher = EmojiManager.getPattern().matcher(s);
while (matcher.find()) {
int from = start + matcher.start();
int to = start + matcher.end();
String emot = editable.subSequence(from, to).toString();
Drawable d = getEmotDrawable(context, emot, SMALL_SCALE);
if (d != null) {
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
editable.setSpan(span, from, to, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
/**
* Returns the text contained within a span and deletes it from the output string
*/
private CharSequence extractSpanText(Editable output, Class kind) {
final Object obj = getLast(output, kind);
// start of the tag
final int where = output.getSpanStart(obj);
// end of the tag
final int len = output.length();
final CharSequence extractedSpanText = output.subSequence(where, len);
output.delete(where, len);
return extractedSpanText;
}
/**
* The default implementation returns the given amount of text from the
* current cursor position in the buffer.
*/
public CharSequence getTextAfterCursor(int length, int flags) {
final Editable content = getEditable();
if (content == null) return null;
int a = Selection.getSelectionStart(content);
int b = Selection.getSelectionEnd(content);
if (a > b) {
int tmp = a;
a = b;
b = tmp;
}
// Guard against the case where the cursor has not been positioned yet.
if (b < 0) {
b = 0;
}
if (b + length > content.length()) {
length = content.length() - b;
}
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
return content.subSequence(b, b + length);
}
return TextUtils.substring(content, b, b + length);
}
/**
* @param editable 变化后的Editable
* @param start text 变化区块的起始index
* @param count text 变化区块的大小
* @param delete 是否是删除
*/
private void afterTextChanged(Editable editable, int start, int count, boolean delete) {
curPos = delete ? start : count + start;
LogUtil.i("atmanager", "afterTextChanged editable = " + editable.toString() + " start = " + start + " count = " + count + " delete = " + delete);
if (ignoreTextChange) {
return;
}
if (delete) {
int before = curPos;//start + count;
if (deleteSegment(before, count)) {
return;
}
AtContactsModel.onDeleteText(before, count);
} else {
if (count <= 0 || editable.length() < start + count) {
return;
}
CharSequence s = editable.subSequence(start, start + count);
if (s == null) {
return;
}
if (s.toString().equals("@")) {
startAtList(false);
}
AtContactsModel.onInsertText(start, editable.toString());
}
}
/**
* @return the line above current cursor
*/
@Nullable
private CharSequence getPrevLine(Editable editable, Layout layout, int currentLine) {
if (currentLine - 1 < 0) return null;
int lineStart = layout.getLineStart(currentLine - 1);
int lineEnd = layout.getLineEnd(currentLine - 1);
return editable.subSequence(lineStart, lineEnd);
}
@Nullable
protected CharSequence getNextLine(Editable editable, Layout layout, int currentLine) {
if (currentLine + 1 > layout.getLineCount() - 1) return null;
int lineStart = layout.getLineStart(currentLine + 1);
int lineEnd = layout.getLineEnd(currentLine + 1);
return editable.subSequence(lineStart, lineEnd);
}
@Nullable
protected CharSequence getWordInCursor() {
int pos = getSelectionStart();
if (pos == -1) return "";
Editable editableText = getEditableText();
int start = pos, end = pos;
while (start > 0 && Character.isLetterOrDigit(editableText.charAt(start))) start--;
while (end < editableText.length() && Character.isLetterOrDigit(editableText.charAt(start)))
end++;
return editableText.subSequence(start, end);
}
/**
* Ensures that a {@link CategorySpan} is in {@param textToSpannify} if required.
* Will firstly remove all existing category spans, and then add back one if necessary.
* In addition, also adds a {@link TtsSpan} to indicate to screen readers that the category
* span has semantic meaning representing a category.
*/
@TargetApi(21)
private void prepareSpans(Editable textToSpannify) {
if (textToSpannify == null) {
return;
}
removeSpans(textToSpannify, CategorySpan.class);
if (Build.VERSION.SDK_INT >= 21) {
removeSpans(textToSpannify, TtsSpan.class);
}
int colonIndex = textToSpannify.toString().indexOf(':');
if (colonIndex > 0) {
CategorySpan span = new CategorySpan(context);
textToSpannify.setSpan(span, 0, colonIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (Build.VERSION.SDK_INT >= 21) {
// For accessibility reasons, make this more clear to screen readers that the
// span we just added semantically represents a category.
CharSequence categoryName = textToSpannify.subSequence(0, colonIndex);
TtsSpan ttsSpan = new TtsSpan.TextBuilder(context.getString(R.string.tts_category_name,
categoryName)).build();
textToSpannify.setSpan(ttsSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
private void markdownLink() {
final EditText et = mContentET;
Editable editable = et.getText();
mLinkSelection = new Selection(et);
CharSequence des = null;
if (!mLinkSelection.isEmpty()) {
des = editable.subSequence(mLinkSelection.start, mLinkSelection.end);
}
AddLinkFragment.newInstance(des).show(getChildFragmentManager(), "add_link_tag");
}
/**
* @param editable 变化后的Editable
* @param start text 变化区块的起始index
* @param count text 变化区块的大小
* @param delete 是否是删除
*/
private void afterTextChanged(Editable editable, int start, int count, boolean delete) {
curPos = delete ? start : count + start;
if (ignoreTextChange) {
return;
}
if (delete) {
int before = start + count;
if (deleteSegment(before, count)) {
return;
}
aitContactsModel.onDeleteText(before, count);
} else {
if (count <= 0 || editable.length() < start + count) {
return;
}
CharSequence s = editable.subSequence(start, start + count);
if (s == null) {
return;
}
if (s.toString().equals("@")) {
// 启动@联系人界面
if (!TextUtils.isEmpty(tid) || robot) {
AitContactSelectorActivity.start(context, tid, robot);
}
}
aitContactsModel.onInsertText(start, s.toString());
}
}
/**
* Create the more chip. The more chip is text that replaces any chips that do not fit in the pre-defined available
* space when the RecipientEditTextView loses focus.
*/
// Visible for testing.
/* package */void createMoreChip()
{
if(mNoChips)
{
createMoreChipPlainText();
return;
}
if(!mShouldShrink)
return;
final ImageSpan[] tempMore=getSpannable().getSpans(0,getText().length(),MoreImageSpan.class);
if(tempMore.length>0)
getSpannable().removeSpan(tempMore[0]);
final DrawableRecipientChip[] recipients=getSortedRecipients();
if(recipients==null||recipients.length<=CHIP_LIMIT)
{
mMoreChip=null;
return;
}
final Spannable spannable=getSpannable();
final int numRecipients=recipients.length;
final int overage=numRecipients-CHIP_LIMIT;
final MoreImageSpan moreSpan=createMoreSpan(overage);
mRemovedSpans=new ArrayList<DrawableRecipientChip>();
int totalReplaceStart=0;
int totalReplaceEnd=0;
final Editable text=getText();
for(int i=numRecipients-overage;i<recipients.length;i++)
{
mRemovedSpans.add(recipients[i]);
if(i==numRecipients-overage)
totalReplaceStart=spannable.getSpanStart(recipients[i]);
if(i==recipients.length-1)
totalReplaceEnd=spannable.getSpanEnd(recipients[i]);
if(mTemporaryRecipients==null||!mTemporaryRecipients.contains(recipients[i]))
{
final int spanStart=spannable.getSpanStart(recipients[i]);
final int spanEnd=spannable.getSpanEnd(recipients[i]);
recipients[i].setOriginalText(text.toString().substring(spanStart,spanEnd));
}
spannable.removeSpan(recipients[i]);
}
if(totalReplaceEnd<text.length())
totalReplaceEnd=text.length();
final int end=Math.max(totalReplaceStart,totalReplaceEnd);
final int start=Math.min(totalReplaceStart,totalReplaceEnd);
final SpannableString chipText=new SpannableString(text.subSequence(start,end));
chipText.setSpan(moreSpan,0,chipText.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(start,end,chipText);
mMoreChip=moreSpan;
// If adding the +more chip goes over the limit, resize accordingly.
if(!isPhoneQuery()&&getLineCount()>mMaxLines)
setMaxLines(getLineCount());
}
/**
* Create the more chip. The more chip is text that replaces any chips that
* do not fit in the pre-defined available space when the
* RecipientEditTextView loses focus.
*/
// Visible for testing.
/* package */ void createMoreChip() {
if (mNoChips) {
createMoreChipPlainText();
return;
}
if (!mShouldShrink) {
return;
}
ImageSpan[] tempMore = getSpannable().getSpans(0, getText().length(), MoreImageSpan.class);
if (tempMore.length > 0) {
getSpannable().removeSpan(tempMore[0]);
}
DrawableRecipientChip[] recipients = getSortedRecipients();
if (recipients == null || recipients.length <= CHIP_LIMIT) {
mMoreChip = null;
return;
}
Spannable spannable = getSpannable();
int numRecipients = recipients.length;
int overage = numRecipients - CHIP_LIMIT;
MoreImageSpan moreSpan = createMoreSpan(overage);
mRemovedSpans = new ArrayList<DrawableRecipientChip>();
int totalReplaceStart = 0;
int totalReplaceEnd = 0;
Editable text = getText();
for (int i = numRecipients - overage; i < recipients.length; i++) {
mRemovedSpans.add(recipients[i]);
if (i == numRecipients - overage) {
totalReplaceStart = spannable.getSpanStart(recipients[i]);
}
if (i == recipients.length - 1) {
totalReplaceEnd = spannable.getSpanEnd(recipients[i]);
}
if (mTemporaryRecipients == null || !mTemporaryRecipients.contains(recipients[i])) {
int spanStart = spannable.getSpanStart(recipients[i]);
int spanEnd = spannable.getSpanEnd(recipients[i]);
recipients[i].setOriginalText(text.toString().substring(spanStart, spanEnd));
}
spannable.removeSpan(recipients[i]);
}
if (totalReplaceEnd < text.length()) {
totalReplaceEnd = text.length();
}
int end = Math.max(totalReplaceStart, totalReplaceEnd);
int start = Math.min(totalReplaceStart, totalReplaceEnd);
SpannableString chipText = new SpannableString(text.subSequence(start, end));
chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(start, end, chipText);
mMoreChip = moreSpan;
// If adding the +more chip goes over the limit, resize accordingly.
if (!isPhoneQuery() && getLineCount() > mMaxLines) {
setMaxLines(getLineCount());
}
}
/**
* Create the more chip. The more chip is text that replaces any chips that
* do not fit in the pre-defined available space when the
* RecipientEditTextView loses focus.
*/
// Visible for testing.
/* package */ void createMoreChip() {
if (mNoChips) {
createMoreChipPlainText();
return;
}
if (!mShouldShrink) {
return;
}
ImageSpan[] tempMore = getSpannable().getSpans(0, getText().length(), MoreImageSpan.class);
if (tempMore.length > 0) {
getSpannable().removeSpan(tempMore[0]);
}
DrawableRecipientChip[] recipients = getSortedRecipients();
if (recipients == null || recipients.length <= CHIP_LIMIT) {
mMoreChip = null;
return;
}
Spannable spannable = getSpannable();
int numRecipients = recipients.length;
int overage = numRecipients - CHIP_LIMIT;
MoreImageSpan moreSpan = createMoreSpan(overage);
mRemovedSpans = new ArrayList<DrawableRecipientChip>();
int totalReplaceStart = 0;
int totalReplaceEnd = 0;
Editable text = getText();
for (int i = numRecipients - overage; i < recipients.length; i++) {
mRemovedSpans.add(recipients[i]);
if (i == numRecipients - overage) {
totalReplaceStart = spannable.getSpanStart(recipients[i]);
}
if (i == recipients.length - 1) {
totalReplaceEnd = spannable.getSpanEnd(recipients[i]);
}
if (mTemporaryRecipients == null || !mTemporaryRecipients.contains(recipients[i])) {
int spanStart = spannable.getSpanStart(recipients[i]);
int spanEnd = spannable.getSpanEnd(recipients[i]);
recipients[i].setOriginalText(text.toString().substring(spanStart, spanEnd));
}
spannable.removeSpan(recipients[i]);
}
if (totalReplaceEnd < text.length()) {
totalReplaceEnd = text.length();
}
int end = Math.max(totalReplaceStart, totalReplaceEnd);
int start = Math.min(totalReplaceStart, totalReplaceEnd);
SpannableString chipText = new SpannableString(text.subSequence(start, end));
chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(start, end, chipText);
mMoreChip = moreSpan;
// If adding the +more chip goes over the limit, resize accordingly.
if (!isPhoneQuery() && getLineCount() > mMaxLines) {
setMaxLines(getLineCount());
}
}