private void applySpacing() { if (this == null || this.originalText == null) return; StringBuilder builder = new StringBuilder(); for (int i = 0; i < originalText.length(); i++) { builder.append(originalText.charAt(i)); if (i + 1 < originalText.length()) { builder.append("\u00A0"); } } SpannableString finalText = new SpannableString(builder.toString()); if (builder.toString().length() > 1) { for (int i = 1; i < builder.toString().length(); i += 2) { finalText.setSpan(new ScaleXSpan((spacing + 1) / 10), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } super.setText(finalText, BufferType.SPANNABLE); setSelection(finalText.length()); }
/** * 字距为任何字符串(技术上,一个简单的方法为CharSequence不使用)的TextView */ private void applyLetterSpacing() { if (this == null || this.originalText == null) return; StringBuilder builder = new StringBuilder(); for(int i = 0; i < originalText.length(); i++) { String c = ""+ originalText.charAt(i); builder.append(c.toLowerCase()); if(i+1 < originalText.length()) { builder.append("\u00A0"); } } SpannableString finalText = new SpannableString(builder.toString()); if(builder.toString().length() > 1) { for(int i = 1; i < builder.toString().length(); i+=2) { finalText.setSpan(new ScaleXSpan((letterSpacing+1)/10), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } super.setText(finalText, BufferType.SPANNABLE); }
private SpannableString applyLetterSpacing(String text) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < text.length(); i++) { builder.append(text.charAt(i)); if (i + 1 < text.length() && !isEmojiCharacter(text.charAt(i))) {//avoid adding the blank code between the emoji code builder.append("\u00A0"); } } SpannableString finalText = new SpannableString(builder.toString()); if (builder.toString().length() > 1) { for (int i = 1; i < builder.toString().length(); i += 2) { if (builder.toString().toCharArray()[i] == 160) {//avoid breaking emoji code, u00A0 is text space finalText.setSpan(new ScaleXSpan((mLetterSpace + 1) / 10), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } return finalText; }
/** * The algorithm which applies the kerning to the {@link TextView} */ private void applyKerning() { if (mOriginalText == null) { return; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < mOriginalText.length(); i++) { builder.append(mOriginalText.charAt(i)); if (i + 1 < mOriginalText.length()) { builder.append("\u00A0"); } } SpannableString finalText = new SpannableString(builder.toString()); if (builder.toString().length() > 1) { for (int i = 1; i < builder.toString().length(); i += 2) { finalText.setSpan(new ScaleXSpan((mKerningFactor) / 10), i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } super.setText(finalText, BufferType.SPANNABLE); }
private SpannableStringBuilder getSpacedOutString(CharSequence text) { final SpannableStringBuilder builder = new SpannableStringBuilder(); final int textLength = text.length(); int lastSpaceIndex = -1; //Insert a space in front of all characters upto the last character //Scale the space without scaling the character to preserve font appearance for (int i = 0; i < textLength - 1; i++) { builder.append(text.charAt(i)); builder.append(" "); lastSpaceIndex += 2; builder.setSpan(new ScaleXSpan(proportion), lastSpaceIndex, lastSpaceIndex + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } //Append the last character if (textLength != 0) builder.append(text.charAt(textLength - 1)); return builder; }
/** * 1. Tests whether the content is set to the expected value. * 2. Tests whether the original content is set to the original value. * 3. Tests that the styles applied have the expected propotion * 4. Tests that the styles have been applied only on the spaces to preserve fonts appearance. * @param expectedSpacedText * @param expectedOriginalText * @param editText */ private void testSpacing(String expectedSpacedText, String expectedOriginalText, SpacedEditText editText) { final Editable editable = editText.getText(); final ScaleXSpan[] spans = editable.getSpans(0, editText.length(), ScaleXSpan.class); assertEquals(expectedSpacedText, editable.toString()); assertEquals(expectedOriginalText, editText.getUnspacedText().toString()); for (ScaleXSpan span: spans){ assertEquals(spacingPropotion, span.getScaleX()); final int spanStart = editable.getSpanStart(span); final int spanEnd = editable.getSpanEnd(span); assertEquals(" ", editable.toString().substring(spanStart, spanEnd)); } }
private void applyLetterSpacing() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < originalText.length(); i++) { builder.append(originalText.charAt(i)); if (i + 1 < originalText.length()) { builder.append('\u00A0'); } } SpannableString finalText = new SpannableString(builder.toString()); if (builder.toString().length() > 1) { for (int i = 1; i < builder.toString().length(); i += 2) { finalText.setSpan(new ScaleXSpan((letterSpacing + 1.0F) / 10.0F), i, i + 1, SPAN_EXCLUSIVE_EXCLUSIVE); } } super.setText(finalText, BufferType.SPANNABLE); }
private SpannableStringBuilder getSpacedOutString(CharSequence text) { SpannableStringBuilder builder = new SpannableStringBuilder(); int textLength = text.length(); int lastSpaceIndex = -1; //Insert a space in front of all characters upto the last character //Scale the space without scaling the character to preserve font appearance for (int i = 0; i < textLength - 1; i++) { builder.append(text.charAt(i)); builder.append(" "); lastSpaceIndex += 2; builder.setSpan(new ScaleXSpan(mProportion), lastSpaceIndex, lastSpaceIndex + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } //Append the last character if (textLength != 0) builder.append(text.charAt(textLength - 1)); return builder; }
/** * 1. Tests whether the content is set to the expected value. * 2. Tests whether the original content is set to the original value. * 3. Tests that the styles applied have the expected proportion * 4. Tests that the styles have been applied only on the spaces to preserve fonts appearance. */ private void testSpacing(String expectedSpacedText, String expectedOriginalText, SpacedEditText editText) { final Editable editable = editText.getText(); final ScaleXSpan[] spans = editable.getSpans(0, editText.length(), ScaleXSpan.class); assertEquals(expectedSpacedText, editable.toString()); assertEquals(expectedOriginalText, editText.getUnspacedText().toString()); for (ScaleXSpan span : spans) { assertEquals(SPACING_PROPORTION, span.getScaleX()); final int spanStart = editable.getSpanStart(span); final int spanEnd = editable.getSpanEnd(span); assertEquals(" ", editable.toString().substring(spanStart, spanEnd)); } }
@Test public void scale_x_should_add_only_one_span() { spanBuilder.scaleX(range, INTEGER_ARG) .apply(); verify((SpanEZ) spanBuilder, times(1)) .addSpan(isA(TargetRange.class), isA(ScaleXSpan.class)); }
/** * @see android.text.style.ScaleXSpan#ScaleXSpan(float) */ public static Span scaleXSize(@FloatRange(from = 0.0) final float proportion) { return new Span(new SpanBuilder() { @Override public Object build() { return new ScaleXSpan(proportion); } }); }
public TextDecorator scaleX(final float proportion, final String... texts) { int index; for (String text : texts) { if (content.contains(text)) { index = content.indexOf(text); decoratedContent.setSpan(new ScaleXSpan(proportion), index, index + text.length(), flags); } } return this; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ac_demo_spannable); TextView tv_1 = findViewById(R.id.tv_1); TextView tv_2 = findViewById(R.id.tv_2); String content = "目前有{numHospital}家医院{numSeller}位咨询师"; content = content.replace("{numHospital}", "28").replace("{numSeller}", "325"); //普通TextView tv_1.setText(content); //spannable处理过的TextView Spanned s = Html.fromHtml(content); int index0 = content.indexOf("前有")+2; int index1 = content.indexOf("家医院") + 3; int index2 = content.indexOf("位咨"); String color = "#79d2be"; SpannableString msp = new SpannableString(s); msp.setSpan(new RelativeSizeSpan(1.25f), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //0.5f表示默认字体大小的一半 msp.setSpan(new RelativeSizeSpan(1.2f), index1,index2 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //0.5f表示默认字体大小的一半 msp.setSpan(new ForegroundColorSpan(Color.parseColor(color)), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色 msp.setSpan(new ForegroundColorSpan(Color.parseColor(color)),index1,index2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色 msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体 msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), index1,index2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体 msp.setSpan(new ScaleXSpan(0.9f), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); msp.setSpan(new ScaleXSpan(0.9f), index1,index2 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv_2.setText(msp); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); final SpannableStringBuilder ssb = new SpannableStringBuilder(); final int flag = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE; int start; int end; // Regular text ssb.append("This text is normal, but "); // Bold text start = ssb.length(); ssb.append("this text is bold"); end = ssb.length(); ssb.setSpan(new StyleSpan(Typeface.BOLD), start, end, flag); // Inline image ssb.append('\n'); start = end + 1; ssb.append('\uFFFC'); // Unicode replacement character end = ssb.length(); ssb.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), start, end, flag); // Stretched text start = end; ssb.append("This text is wide"); end = ssb.length(); ssb.setSpan(new ScaleXSpan(2f), start, end, flag); // Assign to TextView final TextView tv = (TextView) findViewById(R.id.textView); tv.setText(ssb); }
private static void setUpScaleXSpan(Span span, SpannableString ss, int start, int end) { float scaleX = span.getScaleX(); if (Float.floatToRawIntBits(scaleX) != 0) { ss.setSpan( new ScaleXSpan(scaleX), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } }
/** * Update the summary of the preference. */ private void updateSummary() { SpannableString summary = new SpannableString(Application.getAppContext().getString(R.string.button_select_color)); int overlayColor = PreferenceUtil.getSharedPreferenceInt(R.string.key_overlay_color, Color.RED); summary.setSpan(new ForegroundColorSpan(overlayColor), 0, summary.length(), 0); summary.setSpan(new RelativeSizeSpan(1.2f), 0, summary.length(), 0); // MAGIC_NUMBER summary.setSpan(new ScaleXSpan(5), 0, summary.length(), 0); // MAGIC_NUMBER setSummary(summary); }
public static Node scaleX(Float proportion, Object... nodes) { return new SpanNode(new ScaleXSpan(proportion), nodes); }
@Override public StyleEZ scaleX(@NonNull Locator locator, @FloatRange(from = 0.f) float proportion) { ScaleXSpan scaleXSpan = new ScaleXSpan(proportion); addMultipleSpan(locator, scaleXSpan); return this; }
public void setPrefixScaleX(final float prefixScaleX) { this.prefixScaleXSpan = new ScaleXSpan(prefixScaleX); updateView(); }
public StyledText appendScaleX(CharSequence text,float proportion){ return append(text, new ScaleXSpan(proportion)); }
public TextDecorator scaleX(final float proportion, final int start, final int end) { checkIndexOutOfBoundsException(start, end); decoratedContent.setSpan(new ScaleXSpan(proportion), start, end, flags); return this; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ac_demo_spannable); TextView tv_1 = findViewById(R.id.tv_1); TextView tv_2 = findViewById(R.id.tv_2); ///badgeview BadgeView badge = new BadgeView(getActivity()); badge.setTargetView(tv_1); badge.setBadgeCount(4); BadgeView badge2 = new BadgeView(getActivity()); badge2.setTargetView(tv_2); badge2.setBadgeCount(422); /// String content = "目前有{numHospital}家医院{numSeller}位咨询师"; content = content.replace("{numHospital}", "28").replace("{numSeller}", "325"); //普通TextView tv_1.setText(content); //spannable处理过的TextView Spanned s = Html.fromHtml(content); int index0 = content.indexOf("前有")+2; int index1 = content.indexOf("家医院") + 3; int index2 = content.indexOf("位咨"); String color = "#79d2be"; SpannableString msp = new SpannableString(s); msp.setSpan(new RelativeSizeSpan(1.25f), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //0.5f表示默认字体大小的一半 msp.setSpan(new RelativeSizeSpan(1.2f), index1,index2 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //0.5f表示默认字体大小的一半 msp.setSpan(new ForegroundColorSpan(Color.parseColor(color)), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色 msp.setSpan(new ForegroundColorSpan(Color.parseColor(color)),index1,index2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色 msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体 msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), index1,index2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体 msp.setSpan(new ScaleXSpan(0.9f), index0, index1-3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); msp.setSpan(new ScaleXSpan(0.9f), index1,index2 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv_2.setText(msp); }
private SpanPlacementInfo readSingleCharacterStyle(DataInputStream dis) throws IOException { SpanPlacementInfo spi = new SpanPlacementInfo(); spi.start = dis.readInt(); spi.end = dis.readInt(); spi.mode = dis.readInt(); int tag = dis.readInt(); switch (tag) { case -1: return spi; // we does not known this span type case -2: // underlying? int ref = dis.readInt(); spi.span = CharacterStyle.wrap((CharacterStyle) mWrittenTagsReverse.get(ref)); return spi; case 1: // BackgroundColorSpan spi.span = new BackgroundColorSpan(dis.readInt()); break; case 3: // ForegroundColorSpan spi.span = new ForegroundColorSpan(dis.readInt()); break; case 7: // StrikeTroughSpan spi.span = new StrikethroughSpan(); break; case 8: // SuggestionSpan Log.w(TAG, "SuggestionSpan not supported"); break; case 9: // UnderlineSpan spi.span = new UnderlineSpan(); break; case 10: // AbsoluteSizeSpan spi.span = new AbsoluteSizeSpan(dis.readInt(),dis.readBoolean()); break; case 11: spi.span = readDynamicDrawableSpan(dis); break; case 12: // ImageSpan spi.span = readImageSpanData(dis); break; case 13: // LocaleSpan // unsupported break; case 14: // RelativeSizeSpan spi.span = new RelativeSizeSpan(dis.readFloat()); break; case 16: // ScaleXSpan spi.span = new ScaleXSpan(dis.readFloat()); break; case 17: // StyleSpan spi.span = new StyleSpan(dis.readInt()); break; case 18: // SubscriptSpan spi.span = new SubscriptSpan(); break; case 19: // SuperscriptSpan spi.span = new SuperscriptSpan(); break; case 20: // TextAppearanceSpan // spi.span = new TextAppearanceSpan(); break; case 21: // TypefaceSpan String fontFamily = dis.readUTF(); spi.span = new TypefaceSpan(fontFamily); break; case 22: // UrlSpan spi.span = new URLSpan(dis.readUTF()); break; default: spi.span = read(tag,dis); } if (spi.span!=null) { mWrittenTagsReverse.put(mWrittenTagsReverse.size(), spi.span); } return spi; }
public SpanOptions addScaleXSpan(float proportion) { ScaleXSpan span = new ScaleXSpan(proportion); listSpan.add(span); return this; }
public Pair<CharSequence, TextView.BufferType> createLetterSpacing(CharSequence src, TextView.BufferType type){ TextView view = this.view.get(); switch (textTransform){ case LOWERCASE: src = src.toString().toLowerCase(); break; case UPPERCASE: src = src.toString().toUpperCase(); break; } if (letterSpace != NO_LETTER_SPACE && src != null) { final int srcLength = src.length(); if (srcLength > 1) { final String nonBreakingSpace = "\u00A0"; final SpannableStringBuilder builder = src instanceof SpannableStringBuilder ? (SpannableStringBuilder) src : new SpannableStringBuilder((isHtml) ? Html.fromHtml(src.toString()) : src); for (int i = builder.length() - 1; i >= 1; i--) { builder.insert(i, nonBreakingSpace); builder.setSpan(new ScaleXSpan(letterSpace), i, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } if(Build.VERSION.SDK_INT >= 14) { view.setAllCaps(false); } view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); return new Pair<CharSequence, TextView.BufferType>(builder, TextView.BufferType.SPANNABLE); } }else if(src != null){ if (isHtml) { view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); return new Pair<CharSequence, TextView.BufferType>(Html.fromHtml(src.toString()), TextView.BufferType.SPANNABLE); }else if(textTransform != null && textTransform != TRANSFORM.NONE) { view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); return new Pair<CharSequence, TextView.BufferType>(src, TextView.BufferType.SPANNABLE); } } return new Pair<CharSequence, TextView.BufferType>(src, type); }
/** * x缩放 * * @param proportion * @param flags * @return */ public Spannable scaleX(float proportion, int flags) { spans.put(new ScaleXSpan(proportion), flags); return this; }
/** * 缩放X大小 * @param text * @param proportion * @return */ public AndroidSpan drawScaleXSpan(String text, float proportion) { ScaleXSpan span = new ScaleXSpan(proportion); drawSpan(text, span); return this; }