/** * 用本函数代替{@link #setText(CharSequence)} * * @param cs */ public void setMText(CharSequence cs) { text = cs; obList.clear(); // contentList.clear(); ArrayList<IS> isList = new ArrayList<MTextView.IS>(); useDefault = false; if (cs instanceof SpannableString) { SpannableString ss = (SpannableString) cs; ImageSpan[] imageSpans = ss.getSpans(0, ss.length(), ImageSpan.class); for (int i = 0; i < imageSpans.length; i++) { int s = ss.getSpanStart(imageSpans[i]); int e = ss.getSpanEnd(imageSpans[i]); IS iS = new IS(); iS.is = imageSpans[i]; iS.start = s; iS.end = e; isList.add(iS); } } String str = cs.toString(); for (int i = 0, j = 0; i < cs.length(); ) { if (j < isList.size()) { IS is = isList.get(j); if (i < is.start) { Integer cp = str.codePointAt(i); // 支持增补字符 if (Character.isSupplementaryCodePoint(cp)) { i += 2; } else { i++; } obList.add(new String(Character.toChars(cp))); } else if (i >= is.start) { obList.add(is.is); j++; i = is.end; } } else { Integer cp = str.codePointAt(i); if (Character.isSupplementaryCodePoint(cp)) { i += 2; } else { i++; } obList.add(new String(Character.toChars(cp))); } } requestLayout(); }
@Override public boolean onTouch(View v, MotionEvent event) { Layout layout = ((TextView) v).getLayout(); int x = (int) event.getX(); int y = (int) event.getY(); int offset = 0; if (layout != null) { int line = layout.getLineForVertical(y); offset = layout.getOffsetForHorizontal(line, x); } TextView tv = (TextView) v; SpannableString value = SpannableString.valueOf(tv.getText()); LinkMovementMethod.getInstance().onTouchEvent(tv, value, event); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: WeburlSpan[] urlSpans = value.getSpans(0, value.length(), WeburlSpan.class); boolean find = false; int findStart = 0; int findEnd = 0; for (WeburlSpan urlSpan : urlSpans) { int start = value.getSpanStart(urlSpan); int end = value.getSpanEnd(urlSpan); if (start <= offset && offset <= end) { find = true; findStart = start; findEnd = end; break; } } if (find) { BackgroundColorSpan bkcolor = new BackgroundColorSpan(0xff89660f); value.setSpan(bkcolor, findStart, findEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE); ((TextView) v).setText(value); } return find; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: BackgroundColorSpan[] backgroundColorSpans = value.getSpans(0, value.length(), BackgroundColorSpan.class); for (BackgroundColorSpan bkcolor : backgroundColorSpans) { value.removeSpan(bkcolor); ((TextView) v).setText(value); } break; } return false; }
@CalledByNative private void populateUnderlinesFromSpans(CharSequence text, long underlines) { Log.d(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]", text, underlines); if (!(text instanceof SpannableString)) return; SpannableString spannableString = ((SpannableString) text); CharacterStyle spans[] = spannableString.getSpans(0, text.length(), CharacterStyle.class); for (CharacterStyle span : spans) { if (span instanceof BackgroundColorSpan) { nativeAppendBackgroundColorSpan( underlines, spannableString.getSpanStart(span), spannableString.getSpanEnd(span), ((BackgroundColorSpan) span).getBackgroundColor()); } else if (span instanceof UnderlineSpan) { nativeAppendUnderlineSpan( underlines, spannableString.getSpanStart(span), spannableString.getSpanEnd(span)); } } }
private static SpannableString style( Context ctx, HashMap<String, ITypeface> fonts, SpannableString textSpanned, List<CharacterStyle> styles, HashMap<String, List<CharacterStyle>> stylesFor) { if (fonts == null || fonts.size() == 0) { fonts = FONTS; } int startIndex = -1; String fontKey = ""; // remember the position of removed chars ArrayList<RemoveInfo> removed = new ArrayList<RemoveInfo>(); // StringBuilder text = new StringBuilder(textSpanned.toString()); StringBuilder text = new StringBuilder(textSpanned); // find the first "{" while ((startIndex = text.indexOf("{", startIndex + 1)) != -1) { // make sure we are still within the bounds of the text if (text.length() < startIndex + 5) { startIndex = -1; break; } // make sure the found text is a real fontKey if (!text.substring(startIndex + 4, startIndex + 5).equals("-")) { break; } // get the fontKey fontKey = text.substring(startIndex + 1, startIndex + 4); // check if the fontKey is a registeredFont if (fonts.containsKey(fontKey)) { break; } } if (startIndex == -1) { return new SpannableString(text); } // remember total removed chars int removedChars = 0; LinkedList<StyleContainer> styleContainers = new LinkedList<StyleContainer>(); do { // get the information from the iconString int endIndex = text.substring(startIndex).indexOf("}") + startIndex + 1; String iconString = text.substring(startIndex + 1, endIndex - 1); iconString = iconString.replaceAll("-", "_"); try { // get the correct character for this Font and Icon IIcon icon = fonts.get(fontKey).getIcon(iconString); // we can only add an icon which is a font if (icon != null) { char fontChar = icon.getCharacter(); String iconValue = String.valueOf(fontChar); // get just the icon identifier text = text.replace(startIndex, endIndex, iconValue); // store some info about the removed chars removedChars = removedChars + (endIndex - startIndex); removed.add(new RemoveInfo(startIndex, (endIndex - startIndex - 1), removedChars)); // add the current icon to the container styleContainers.add( new StyleContainer(startIndex, startIndex + 1, iconString, fonts.get(fontKey))); } } catch (IllegalArgumentException e) { Log.w(Iconics.TAG, "Wrong icon name: " + iconString); } // reset fontKey so we can react if we are at the end but haven't found any more matches fontKey = null; // check the rest of the text for matches while ((startIndex = text.indexOf("{", startIndex + 1)) != -1) { // make sure we are still within the bounds if (text.length() < startIndex + 5) { startIndex = -1; break; } // check if the 5. char is a "-" if (text.substring(startIndex + 4, startIndex + 5).equals("-")) { // get the fontKey fontKey = text.substring(startIndex + 1, startIndex + 4); // check if the fontKey is registered if (fonts.containsKey(fontKey)) { break; } } } } while (startIndex != -1 && fontKey != null); SpannableString sb = new SpannableString(text); // reapply all previous styles for (StyleSpan span : textSpanned.getSpans(0, textSpanned.length(), StyleSpan.class)) { int spanStart = newSpanPoint(textSpanned.getSpanStart(span), removed); int spanEnd = newSpanPoint(textSpanned.getSpanEnd(span), removed); if (spanStart >= 0 && spanEnd > 0) { sb.setSpan(span, spanStart, spanEnd, textSpanned.getSpanFlags(span)); } } // set all the icons and styles for (StyleContainer styleContainer : styleContainers) { sb.setSpan( new IconicsTypefaceSpan("sans-serif", styleContainer.getFont().getTypeface(ctx)), styleContainer.getStartIndex(), styleContainer.getEndIndex(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if (stylesFor.containsKey(styleContainer.getIcon())) { for (CharacterStyle style : stylesFor.get(styleContainer.getIcon())) { sb.setSpan( CharacterStyle.wrap(style), styleContainer.getStartIndex(), styleContainer.getEndIndex(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (styles != null) { for (CharacterStyle style : styles) { sb.setSpan( CharacterStyle.wrap(style), styleContainer.getStartIndex(), styleContainer.getEndIndex(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } // sb = applyKerning(sb, 1); return sb; }