@Override public boolean onTouchEvent(MotionEvent event) { CharSequence text = getText(); int action = event.getAction(); if (!(text instanceof Spannable)) { return super.onTouchEvent(event); } Spannable buffer = (Spannable) text; if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) { TextView widget = this; int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); URLSpan[] link = buffer.getSpans(off, off, URLSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_UP) { if (mCurrentLink == link[0]) { link[0].onClick(widget); } mCurrentLink = null; buffer.removeSpan(mLinkFocusStyle); } else if (action == MotionEvent.ACTION_DOWN) { mCurrentLink = link[0]; buffer.setSpan( mLinkFocusStyle, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } return true; } } mCurrentLink = null; buffer.removeSpan(mLinkFocusStyle); return super.onTouchEvent(event); }
public static Spannable getSmiledText(Context context, CharSequence text) { Spannable spannable = spannableFactory.newSpannable(text); for (Entry entry : ANDROID_EMOTICONS.entrySet()) { Matcher matcher = ((Pattern) entry.getKey()).matcher(spannable); while (matcher.find()) { for (Object obj : (ImageSpan[]) spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) { if (spannable.getSpanStart(obj) < matcher.start() || spannable.getSpanEnd(obj) > matcher.end()) { Object obj2 = null; break; } spannable.removeSpan(obj); } int i = 1; if (obj2 != null) { spannable.setSpan( new ImageSpan(context, ((Integer) entry.getValue()).intValue()), matcher.start(), matcher.end(), 33); } } } return spannable; }
/** * replace existing spannable with smiles * * @param context * @param spannable * @return */ public static boolean addSmiles(Context context, Spannable spannable) { boolean hasChanges = false; for (Entry<Pattern, Integer> entry : emoticons.entrySet()) { Matcher matcher = entry.getKey().matcher(spannable); while (matcher.find()) { boolean set = true; for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) if (spannable.getSpanStart(span) >= matcher.start() && spannable.getSpanEnd(span) <= matcher.end()) spannable.removeSpan(span); else { set = false; break; } if (set) { hasChanges = true; spannable.setSpan( new ImageSpan(context, entry.getValue()), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } return hasChanges; }
public boolean addImages(Context context, Spannable spannable) { Pattern refImg = Pattern.compile("\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E"); boolean hasChanges = false; Matcher matcher = refImg.matcher(spannable); while (matcher.find()) { boolean set = true; for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) { if (spannable.getSpanStart(span) >= matcher.start() && spannable.getSpanEnd(span) <= matcher.end()) { spannable.removeSpan(span); } else { set = false; break; } } String resname = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim(); int id = context.getResources().getIdentifier(resname, "drawable", context.getPackageName()); Drawable icon = context.getResources().getDrawable(id); // ,this.getTheme()); icon.setBounds(0, 0, tv_test1.getLineHeight(), tv_test1.getLineHeight()); if (set) { hasChanges = true; spannable.setSpan( new ImageSpan(icon, ImageSpan.ALIGN_BASELINE), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } return hasChanges; }
public static void formatSignificant( @Nonnull final Spannable spannable, @Nullable final RelativeSizeSpan insignificantRelativeSizeSpan) { spannable.removeSpan(SIGNIFICANT_SPAN); if (insignificantRelativeSizeSpan != null) spannable.removeSpan(insignificantRelativeSizeSpan); final Matcher m = P_SIGNIFICANT.matcher(spannable); if (m.find()) { final int pivot = m.group().length(); if (pivot > 0) spannable.setSpan(SIGNIFICANT_SPAN, 0, pivot, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (spannable.length() > pivot && insignificantRelativeSizeSpan != null) spannable.setSpan( insignificantRelativeSizeSpan, pivot, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } }
/** * 清除textview链接的下划线 * * @param textView */ public static void removeLinkUnderline(TextView textView) { Spannable s = Spannable.Factory.getInstance().newSpannable(textView.getText()); URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class); for (URLSpan span : spans) { int start = s.getSpanStart(span); int end = s.getSpanEnd(span); s.removeSpan(span); span = new TweetURLSpan(span.getURL()); s.setSpan(span, start, end, 0); } textView.setText(s); }
/** * Removes any {@link android.text.style.URLSpan}s from the Spannable and replaces them with a * non-underline version {@link LinkStyleSpan} which calls the supplied listener when clicked. */ public static void stripUnderlinesAndLinkUrls( Spannable input, View.OnClickListener onClickListener) { final URLSpan[] urls = input.getSpans(0, input.length(), URLSpan.class); for (URLSpan span : urls) { final int start = input.getSpanStart(span); final int end = input.getSpanEnd(span); input.removeSpan(span); input.setSpan( new LinkStyleSpan(onClickListener), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } }
/** * Scans the text of the provided Spannable and turns all occurrences of the link types indicated * in the mask into clickable links. If the mask is nonzero, it also removes any existing URLSpans * attached to the Spannable, to avoid problems if you call it repeatedly on the same text. */ public static final boolean addLinks(Spannable text, int mask) { if (mask == 0) { return false; } URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class); for (int i = old.length - 1; i >= 0; i--) { text.removeSpan(old[i]); } ArrayList<LinkSpec> links = new ArrayList<LinkSpec>(); if ((mask & WEB_URLS) != 0) { gatherLinks( links, text, MyPatterns.WEB_URL, new String[] {"http://", "https://", "rtsp://"}, sUrlMatchFilter, null); } if ((mask & EMAIL_ADDRESSES) != 0) { gatherLinks(links, text, Patterns.EMAIL_ADDRESS, new String[] {"mailto:"}, null, null); } if ((mask & PHONE_NUMBERS) != 0) { gatherLinks( links, text, Patterns.PHONE, new String[] {"tel:"}, sPhoneNumberMatchFilter, sPhoneNumberTransformFilter); } if ((mask & MAP_ADDRESSES) != 0) { gatherMapLinks(links, text); } pruneOverlaps(links); if (links.size() == 0) { return false; } for (LinkSpec link : links) { applyLink(link.url, link.start, link.end, text); } return true; }
private void stripUnderlines(TextView textView) { Spannable s = (Spannable) textView.getText(); URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class); for (URLSpan span : spans) { int start = s.getSpanStart(span); int end = s.getSpanEnd(span); s.removeSpan(span); span = new URLSpanNoUnderline(span.getURL()); s.setSpan(span, start, end, 0); } textView.setText(s); }
public static Spannable changeHyperlinkColor( String content, Html.ImageGetter imageGetter, Html.TagHandler tagHandler, int color) { Spannable s = (Spannable) Html.fromHtml(content, imageGetter, tagHandler); URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class); for (URLSpan span : spans) { int start = s.getSpanStart(span); int end = s.getSpanEnd(span); s.removeSpan(span); span = new URLSpanNoUnderline(span.getURL(), color); s.setSpan(span, start, end, 0); } return s; }
public static Spannable recentMessage( String content, Html.ImageGetter imageGetter, Html.TagHandler tagHandler) { String parse = parseNoMonkeyImage(content); Spannable s = (Spannable) Html.fromHtml(parse, imageGetter, null); URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class); for (URLSpan span : spans) { int start = s.getSpanStart(span); int end = s.getSpanEnd(span); s.removeSpan(span); span = new URLSpanNoUnderline(span.getURL(), 0xff999999); s.setSpan(span, start, end, 0); } return s; }
public static void removeSpans(TextView textView) { CharSequence t = textView.getText(); if (t instanceof Spannable) { Spannable span = (Spannable) t; URLSpan[] old = span.getSpans(0, span.length(), URLSpan.class); for (int i = old.length - 1; i >= 0; i--) { span.removeSpan(old[i]); } } else { SpannableString span = SpannableString.valueOf(t); URLSpan[] old = span.getSpans(0, span.length(), URLSpan.class); for (int i = old.length - 1; i >= 0; i--) { span.removeSpan(old[i]); } } }
public void run() { Spannable buf = mBuffer; if (buf != null) { int st = Selection.getSelectionStart(buf); int en = Selection.getSelectionEnd(buf); int start = buf.getSpanStart(TextKeyListener.ACTIVE); int end = buf.getSpanEnd(TextKeyListener.ACTIVE); if (st == start && en == end) { Selection.setSelection(buf, Selection.getSelectionEnd(buf)); } buf.removeSpan(Timeout.this); } }
public static CharSequence getHtmlText(String text) { // fixes an android bug (?): text layout fails on text with nested style tags text = removeNestedTags(text, new String[] {"i", "b", "strong"}); final Spanned htmlText = Html.fromHtml(text); if (htmlText.getSpans(0, htmlText.length(), URLSpan.class).length == 0) { return htmlText; } final Spannable newHtmlText = Spannable.Factory.getInstance().newSpannable(htmlText); for (URLSpan span : newHtmlText.getSpans(0, newHtmlText.length(), URLSpan.class)) { final int start = newHtmlText.getSpanStart(span); final int end = newHtmlText.getSpanEnd(span); final int flags = newHtmlText.getSpanFlags(span); final String url = NetworkLibrary.Instance().rewriteUrl(span.getURL(), true); newHtmlText.removeSpan(span); newHtmlText.setSpan(new URLSpan(url), start, end, flags); } return newHtmlText; }
private static void fixLinks(Spannable spannable) { for (URLSpan span : spannable.getSpans(0, spannable.length(), URLSpan.class)) { final String url = span.getURL(); int start = spannable.getSpanStart(span); int end = spannable.getSpanEnd(span); int flags = spannable.getSpanFlags(span); URLSpan newSpan = new URLSpan(url) { @Override public void updateDrawState(TextPaint paramTextPaint) { super.updateDrawState(paramTextPaint); paramTextPaint.setUnderlineText(false); paramTextPaint.setColor(0xff006FC8); } }; spannable.removeSpan(span); spannable.setSpan(newSpan, start, end, flags); } }
public void setOrRemoveSpoilerSpans( SpoilerRobotoTextView commentView, Spannable text, int endOfLink) { // add 2 to end of link since there is a white space between the link text and the spoiler ForegroundColorSpan[] foregroundColors = text.getSpans(endOfLink + 2, endOfLink + 2, ForegroundColorSpan.class); if (foregroundColors.length > 0) { text.removeSpan(foregroundColors[0]); commentView.setText(text); } else { for (int i = 0; i < storedSpoilerStarts.size(); i++) { if (storedSpoilerStarts.get(i) < endOfLink + 2 && storedSpoilerEnds.get(i) > endOfLink + 2) { text.setSpan( storedSpoilerSpans.get(i), storedSpoilerStarts.get(i), storedSpoilerEnds.get(i), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } } commentView.setText(text); } }
/** * When the user selects a section of the text, this method is used to toggle the defined style on * it. If the selected text already has the style applied, we remove it, otherwise we apply it. * * @param style The styles that should be toggled on the selected text. */ private void toggleStyle(int style) { // Gets the current cursor position, or the starting position of the // selection int selectionStart = this.getSelectionStart(); // Gets the current cursor position, or the end position of the // selection // Note: The end can be smaller than the start int selectionEnd = this.getSelectionEnd(); // Reverse if the case is what's noted above if (selectionStart > selectionEnd) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } // The selectionEnd is only greater then the selectionStart position // when the user selected a section of the text. Otherwise, the 2 // variables // should be equal (the cursor position). if (selectionEnd > selectionStart) { Spannable str = this.getText(); boolean exists = false; StyleSpan[] styleSpans; switch (style) { case STYLE_BOLD: styleSpans = str.getSpans(selectionStart, selectionEnd, StyleSpan.class); // If the selected text-part already has BOLD style on it, then // we need to disable it for (int i = 0; i < styleSpans.length; i++) { if (styleSpans[i].getStyle() == android.graphics.Typeface.BOLD) { str.removeSpan(styleSpans[i]); exists = true; } } // Else we set BOLD style on it if (!exists) { str.setSpan( new StyleSpan(android.graphics.Typeface.BOLD), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } this.setSelection(selectionStart, selectionEnd); break; case STYLE_ITALIC: styleSpans = str.getSpans(selectionStart, selectionEnd, StyleSpan.class); // If the selected text-part already has ITALIC style on it, // then we need to disable it for (int i = 0; i < styleSpans.length; i++) { if (styleSpans[i].getStyle() == android.graphics.Typeface.ITALIC) { str.removeSpan(styleSpans[i]); exists = true; } } // Else we set ITALIC style on it if (!exists) { str.setSpan( new StyleSpan(android.graphics.Typeface.ITALIC), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } this.setSelection(selectionStart, selectionEnd); break; case STYLE_UNDERLINED: UnderlineSpan[] underSpan = str.getSpans(selectionStart, selectionEnd, UnderlineSpan.class); // If the selected text-part already has UNDERLINE style on it, // then we need to disable it for (int i = 0; i < underSpan.length; i++) { str.removeSpan(underSpan[i]); exists = true; } // Else we set UNDERLINE style on it if (!exists) { str.setSpan( new UnderlineSpan(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); } this.setSelection(selectionStart, selectionEnd); break; } } }
/** Resets all meta state to inactive. */ public static void resetMetaState(Spannable text) { text.removeSpan(CAP); text.removeSpan(ALT); text.removeSpan(SYM); text.removeSpan(SELECTING); }
/** * Stop selecting text. This does not actually collapse the selection; call {@link * android.text.Selection#setSelection} too. * * @hide pending API review */ public static void stopSelecting(View view, Spannable content) { content.removeSpan(SELECTING); }
private static void resetLock(Spannable content, Object what) { int current = content.getSpanFlags(what); if (current == LOCKED) content.removeSpan(what); }
private static void adjust(Spannable content, Object what) { int current = content.getSpanFlags(what); if (current == PRESSED) content.setSpan(what, 0, 0, USED); else if (current == RELEASED) content.removeSpan(what); }
@Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_CANCEL) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_UP) { // 按下后松开,移除所有 BackgroundColorSpan。 BackgroundColorSpan[] backgroundColorSpans = buffer.getSpans(0, buffer.length(), BackgroundColorSpan.class); for (BackgroundColorSpan bkcolor : backgroundColorSpans) { buffer.removeSpan(bkcolor); } // Selection.removeSelection(buffer); link[0].onClick(widget); } else if (action == MotionEvent.ACTION_DOWN) { // 按下,给按下的 ClickableSpan 设置 BackgroundColorSpan。 /* Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); */ BackgroundColorSpan bkcolor = new BackgroundColorSpan(0xff89660f); buffer.setSpan( bkcolor, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0]), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } else if (action == MotionEvent.ACTION_CANCEL) { // 按下不松开而是移动,则变成取消事件,移除所有 BackgroundColorSpan。 BackgroundColorSpan[] backgroundColorSpans = buffer.getSpans(0, buffer.length(), BackgroundColorSpan.class); for (BackgroundColorSpan bkcolor : backgroundColorSpans) { buffer.removeSpan(bkcolor); } } return true; } else { BackgroundColorSpan[] backgroundColorSpans = buffer.getSpans(0, buffer.length(), BackgroundColorSpan.class); for (BackgroundColorSpan bkcolor : backgroundColorSpans) { buffer.removeSpan(bkcolor); } // Selection.removeSelection(buffer); } } return super.onTouchEvent(widget, buffer, event); }
/** * Applies formatting to selected text, or marks the entry for a new text style at the current * cursor position * * @param toggleButton button from formatting bar * @param tag HTML tag name for text style */ private void onFormatButtonClick(ToggleButton toggleButton, String tag) { Spannable s = mContentEditText.getText(); if (s == null) return; int selectionStart = mContentEditText.getSelectionStart(); mStyleStart = selectionStart; int selectionEnd = mContentEditText.getSelectionEnd(); if (selectionStart > selectionEnd) { int temp = selectionEnd; selectionEnd = selectionStart; selectionStart = temp; } Class styleClass = null; if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG) || tag.equals(TAG_FORMAT_BAR_BUTTON_EM)) styleClass = StyleSpan.class; else if (tag.equals(TAG_FORMAT_BAR_BUTTON_UNDERLINE)) styleClass = WPUnderlineSpan.class; else if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRIKE)) styleClass = StrikethroughSpan.class; else if (tag.equals(TAG_FORMAT_BAR_BUTTON_QUOTE)) styleClass = QuoteSpan.class; if (styleClass == null) return; Object[] allSpans = s.getSpans(selectionStart, selectionEnd, styleClass); boolean textIsSelected = selectionEnd > selectionStart; if (mIsLocalDraft) { // Local drafts can use the rich text editor. Yay! boolean shouldAddSpan = true; for (Object span : allSpans) { if (span instanceof StyleSpan) { StyleSpan styleSpan = (StyleSpan) span; if ((styleSpan.getStyle() == Typeface.BOLD && !tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG)) || (styleSpan.getStyle() == Typeface.ITALIC && !tag.equals(TAG_FORMAT_BAR_BUTTON_EM))) { continue; } } if (!toggleButton.isChecked() && textIsSelected) { // If span exists and text is selected, remove the span s.removeSpan(span); shouldAddSpan = false; break; } else if (!toggleButton.isChecked()) { // Remove span at cursor point if button isn't checked Object[] spans = s.getSpans(mStyleStart - 1, mStyleStart, styleClass); for (Object removeSpan : spans) { selectionStart = s.getSpanStart(removeSpan); selectionEnd = s.getSpanEnd(removeSpan); s.removeSpan(removeSpan); } } } if (shouldAddSpan) { if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG)) { s.setSpan( new StyleSpan(android.graphics.Typeface.BOLD), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (tag.equals(TAG_FORMAT_BAR_BUTTON_EM)) { s.setSpan( new StyleSpan(android.graphics.Typeface.ITALIC), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else { try { s.setSpan( styleClass.newInstance(), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } catch (java.lang.InstantiationException e) { AppLog.e(T.POSTS, e); } catch (IllegalAccessException e) { AppLog.e(T.POSTS, e); } } } } else { // Add HTML tags when editing an existing post String startTag = "<" + tag + ">"; String endTag = "</" + tag + ">"; Editable content = mContentEditText.getText(); if (textIsSelected) { content.insert(selectionStart, startTag); content.insert(selectionEnd + startTag.length(), endTag); toggleButton.setChecked(false); mContentEditText.setSelection(selectionEnd + startTag.length() + endTag.length()); } else if (toggleButton.isChecked()) { content.insert(selectionStart, startTag); mContentEditText.setSelection(selectionEnd + startTag.length()); } else if (!toggleButton.isChecked()) { content.insert(selectionEnd, endTag); mContentEditText.setSelection(selectionEnd + endTag.length()); } } }
public void onSpanChanged(Spannable buf, Object what, int s, int e, int start, int stop) { if (what == Selection.SELECTION_END) { buf.removeSpan(TextKeyListener.ACTIVE); removeTimeouts(buf); } }
@Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { if (mGray == null) { mGray = new BackgroundColorSpan( widget.getContext().getResources().getColor(R.color.selector_gray)); } mIsLinkHit = false; int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP) { int x = (int) event.getX(); int y = (int) event.getY(); /*if (DEBUG) { Log.d(TAG, "x = " + x + " y = " + y); }*/ x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); /*if (DEBUG) { Log.d(TAG, "x = " + x + " y = " + y); }*/ x += widget.getScrollX(); y += widget.getScrollY(); int line = widget.getLayout().getLineForVertical(y); int offset = widget.getLayout().getOffsetForHorizontal(line, x); ClickableSpan[] spans = buffer.getSpans(offset, offset, ClickableSpan.class); /*if (DEBUG) { Log.d(TAG, "x = " + x + " y = " + y); Log.d(TAG, "line = " + line + " offset = " + offset); Log.d(TAG, "spans.lenth = " + spans.length); }*/ if (spans.length != 0) { int start = buffer.getSpanStart(spans[0]); int end = buffer.getSpanEnd(spans[0]); mIsLinkHit = true; if (action == MotionEvent.ACTION_DOWN) { /*if (DEBUG) { Log.d(TAG, "Down event detected"); }*/ buffer.setSpan(mGray, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (action == MotionEvent.ACTION_UP) { /*if (DEBUG) { Log.d(TAG, "Up event detected"); }*/ spans[0].onClick(widget); buffer.removeSpan(mGray); } return true; } } else { buffer.removeSpan(mGray); } return Touch.onTouchEvent(widget, buffer, event); }
private static void removeUnprintable(Spannable spannable, int start, int end) { UnprintableSpan[] spans = spannable.getSpans(start, end, UnprintableSpan.class); for (UnprintableSpan s : spans) spannable.removeSpan(s); }
private static void removeTimeouts(Spannable buf) { Timeout[] timeout = buf.getSpans(0, buf.length(), Timeout.class); for (int i = 0; i < timeout.length; i++) { Timeout t = timeout[i]; t.removeCallbacks(t); t.mBuffer = null; buf.removeSpan(t); } }