`

高效快捷解决一个TextView显示多种字体的控件SpannableTextView

阅读更多
这个控件本人强烈推荐,它会使得布局非常的简单且高效;
下面这个布局如果是你,你会用多少层?多少控件生成?



告诉你吧,一个SpannableTextView控件就搞定了!

它把TextView和Spannable封装在了一起,可以在一个TextView中显示不同的字体颜色,大小,背景色等;
它支持如下样式:

* Babushka Method      Internal Span
*     textSize            AbsoluteSizeSpan
*     textColor           ForegroundColorSpan
*     textSizeRelative    RelativeSizeSpan
*     backgroundColor     BackgroundColorSpan
*     style               StyleSpan
*     underline           UnderlineSpan
*     strike              StrikethroughSpan
*     superscript         SuperscriptSpan
*     subscript           SubscriptSpan

用法也很简单:
/**
     * 为一个TextView设置多种字体(大小,颜色,背景色等)
     * 
     * @param tv
     * @param title
     * @param content
     */
    public void createSpannableTextView(SpannableTextView tv, String title, String content)
    {

        // clear pieces
        tv.reset();
        // Add the first piece
        tv.addPiece(new SpannableTextView.Piece.Builder(title).textColor(App.res.getColor(R.color.text_color_c2))
                .textSize((int) App.res.getDimension(R.dimen.font_xbig)).build());

        // Add the second piece
        tv.addPiece(new SpannableTextView.Piece.Builder(content).textColor(App.res.getColor(R.color.text_color_c8))
                .textSize((int) App.res.getDimension(R.dimen.font_middle)).build());

        // Display the final, styled text
        tv.display();
    }


SpannableTextView tv = null;
                tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView0));
                context.createSpannableTextView(tv, "血糖\n", "记录血糖指数");
                tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView1));
                context.createSpannableTextView(tv, "血压\n", "记录血压指数");
                tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView2));
                context.createSpannableTextView(tv, "体重\n", "记录体重");
                tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView3));
                context.createSpannableTextView(tv, "饮食\n", "记录日常饮食");
                tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView4));
                context.createSpannableTextView(tv, "运动\n", "记录运动时间");


<cn.tangdada.tangbang.widget.SpannableTextView
                android:id="@+id/spannableTextView0"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center_vertical"
                android:background="@drawable/line_bottom"
                android:drawableRight="@drawable/arrow_right"
                android:drawableLeft="@drawable/icon_0"
                android:gravity="center_vertical"
                android:lineSpacingExtra="4dp"
                android:paddingRight="16dp"
                android:singleLine="false" />


源码:
package cn.tangdada.tangbang.widget;

/*
 * Copyright (C) 2014 Henrique Boregio.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Henrique Boregio (hboregio@gmail.com)
 */

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * usage:
 * 
 * <pre>
 * SpannableTextView tv = (SpannableTextView) findViewById(R.id.spannable_textview);
 * 
 * // Add the first piece &quot;Central Park&quot;
 * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;Central Park, NY\n&quot;).textColor(Color.parseColor(&quot;#414141&quot;)).build());
 * 
 * // Add the second piece &quot;1.2 mi&quot;
 * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;1.2 mi &quot;).textColor(Color.parseColor(&quot;#0081E2&quot;)).textSizeRelative(0.9f).build());
 * 
 * // Add the third piece &quot;from here&quot;
 * tv.addPiece(new SpannableTextView.Piece.Builder(&quot;from here&quot;).textColor(Color.parseColor(&quot;#969696&quot;)).textSizeRelative(0.9f).build());
 * 
 * // Display the final, styled text
 * tv.display();
 * </pre>
 * 
 * <pre>
 * // grab the Piece at position 1
 * Piece piece = babushka.getPiece(1);
 * 
 * // modify it's text
 * piece.setText(&quot;1.9 km &quot;);
 * 
 * // you must always call display after you alter a Piece's text
 * tv.display();
 * </pre>
 * 
 * <pre>
 * Babushka Method      Internal Span
 *     textSize            AbsoluteSizeSpan
 *     textColor           ForegroundColorSpan
 *     textSizeRelative    RelativeSizeSpan
 *     backgroundColor     BackgroundColorSpan
 *     style               StyleSpan
 *     underline           UnderlineSpan
 *     strike              StrikethroughSpan
 *     superscript         SuperscriptSpan
 *     subscript           SubscriptSpan
 * </pre>
 * 
 * BabushkaText is a TextView which lets you customize the styling of parts of your text via Spannables, but without the
 * hassle of having to deal directly with Spannable themselves.
 * 
 * The idea behind a BabushkaText is that it is made up of {@code Piece}s. Each Piece represents a section of the final
 * text displayed by this TextView, and each Piece may be styled independently from the other Pieces. When you put it
 * all together, the final results is still a a single TextView, but with a a very different graphic output.
 * 
 * 
 * https://github.com/quiqueqs/BabushkaText
 */
public class SpannableTextView extends TextView
{

    // some default params
    private static int DEFAULT_ABSOLUTE_TEXT_SIZE;

    private static float DEFAULT_RELATIVE_TEXT_SIZE = 1;

    private List<Piece> mPieces;

    /**
     * Create a new instance of a this class
     * 
     * @param context
     */
    public SpannableTextView(Context context)
    {
        super(context);
        init();
    }

    public SpannableTextView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init();
    }

    public SpannableTextView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init()
    {
        mPieces = new ArrayList<Piece>();
        SpannableTextView.DEFAULT_ABSOLUTE_TEXT_SIZE = (int) getTextSize();
    }

    /**
     * Use this method to add a {@link SpannableTextView.BabushkaText.Piece} to a BabushkaText. Each
     * {@link SpannableTextView.BabushkaText.Piece } is added sequentially, so the order you call this method matters.
     * 
     * @param aPiece the Piece
     */
    public void addPiece(Piece aPiece)
    {
        mPieces.add(aPiece);
    }

    /**
     * Adds a Piece at this specific location. The underlying data structure is a {@link java.util.List}, so expect the
     * same type of behaviour.
     * 
     * @param aPiece the Piece to add.
     * @param location the index at which to add.
     */
    public void addPiece(Piece aPiece, int location)
    {
        mPieces.add(location, aPiece);
    }

    /**
     * Replaces the Piece at the specified location with this new Piece. The underlying data structure is a
     * {@link java.util.List}, so expect the same type of behaviour.
     * 
     * @param newPiece the Piece to insert.
     * @param location the index at which to insert.
     */
    public void replacePieceAt(int location, Piece newPiece)
    {
        mPieces.set(location, newPiece);
    }

    /**
     * Removes the Piece at this specified location. The underlying data structure is a {@link java.util.List}, so
     * expect the same type of behaviour.
     * 
     * @param location the index of the Piece to remove
     */
    public void removePiece(int location)
    {
        mPieces.remove(location);
    }

    /**
     * Clear all the Pieces, same as reset()
     */
    public void clearPiece()
    {
        mPieces.clear();
    }

    /**
     * Get a specific {@link SpannableTextView.BabushkaText.Piece} in position index.
     * 
     * @param location position of Piece (0 based)
     * @return Piece o null if invalid index
     */
    public Piece getPiece(int location)
    {
        if (location >= 0 && location < mPieces.size())
        {
            return mPieces.get(location);
        }

        return null;
    }

    /**
     * Call this method when you're done adding {@link SpannableTextView.BabushkaText.Piece}s and want this TextView to
     * display the final, styled version of it's String contents.
     * 
     * You MUST also call this method whenever you make a modification to the text of a Piece that has already been
     * displayed.
     */
    public void display()
    {

        // generate the final string based on the pieces
        StringBuilder builder = new StringBuilder();
        for (Piece aPiece : mPieces)
        {
            builder.append(aPiece.text);
        }

        // apply spans
        int cursor = 0;
        SpannableString finalString = new SpannableString(builder.toString());
        for (Piece aPiece : mPieces)
        {
            applySpannablesTo(aPiece, finalString, cursor, cursor + aPiece.text.length());
            cursor += aPiece.text.length();
        }

        // set the styled text
        setText(finalString);
    }

    private void applySpannablesTo(Piece aPiece, SpannableString finalString, int start, int end)
    {

        if (aPiece.subscript)
        {
            finalString.setSpan(new SubscriptSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        if (aPiece.superscript)
        {
            finalString.setSpan(new SuperscriptSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        if (aPiece.strike)
        {
            finalString.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        if (aPiece.underline)
        {
            finalString.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        // style
        finalString.setSpan(new StyleSpan(aPiece.style), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        // absolute text size
        finalString.setSpan(new AbsoluteSizeSpan(aPiece.textSize), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        // relative text size
        finalString.setSpan(new RelativeSizeSpan(aPiece.textSizeRelative), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        // text color
        finalString.setSpan(new ForegroundColorSpan(aPiece.textColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        // background color
        if (aPiece.backgroundColor != -1)
        {
            finalString.setSpan(new BackgroundColorSpan(aPiece.backgroundColor), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }

    /**
     * Resets the styling of this view and sets it's content to an empty String.
     */
    public void reset()
    {
        mPieces = new ArrayList<Piece>();
        setText("");
    }

    /**
     * Change text color of all pieces of textview.
     */
    public void changeTextColor(int textColor)
    {
        for (Piece mPiece : mPieces)
        {
            mPiece.setTextColor(textColor);
        }
        display();
    }

    /**
     * A Piece represents a part of the text that you want to style. Say for example you want this BabushkaText to
     * display "Hello World" such that "Hello" is displayed in Bold and "World" is displayed in Italics. Since these
     * have different styles, they are both separate Pieces.
     * 
     * You create a Piece by using it's {@link SpannableTextView.BabushkaText.Piece.Builder}
     * 
     */
    public static class Piece
    {

        private String text;

        private int textColor;

        private final int textSize;

        private final int backgroundColor;

        private final float textSizeRelative;

        private final int style;

        private final boolean underline;

        private final boolean superscript;

        private final boolean strike;

        private final boolean subscript;

        public Piece(Builder builder)
        {
            this.text = builder.text;
            this.textSize = builder.textSize;
            this.textColor = builder.textColor;
            this.backgroundColor = builder.backgroundColor;
            this.textSizeRelative = builder.textSizeRelative;
            this.style = builder.style;
            this.underline = builder.underline;
            this.superscript = builder.superscript;
            this.subscript = builder.subscript;
            this.strike = builder.strike;
        }

        /**
         * Sets the text of this Piece. If you're creating a new Piece, you should do so using it's
         * {@link SpannableTextView.BabushkaText.Piece.Builder}.
         * 
         * Use this method if you want to modify the text of an existing Piece that is already displayed. After doing
         * so, you MUST call {@code display()} for the changes to show up.
         * 
         * @param text the text to display
         */
        public void setText(String text)
        {
            this.text = text;
        }

        /**
         * Sets the text color of this Piece. If you're creating a new Piece, you should do so using it's
         * {@link SpannableTextView.BabushkaText.Piece.Builder}.
         * 
         * Use this method if you want to change the text color of an existing Piece that is already displayed. After
         * doing so, you MUST call {@code display()} for the changes to show up.
         * 
         * @param color of text (it is NOT android Color resources ID, use getResources().getColor(R.color.colorId) for
         *            it)
         */
        public void setTextColor(int textColor)
        {
            this.textColor = textColor;
        }

        /**
         * Builder of Pieces
         */
        public static class Builder
        {

            // required
            private final String text;

            // optional
            private int textSize = DEFAULT_ABSOLUTE_TEXT_SIZE;

            private int textColor = Color.BLACK;

            private int backgroundColor = -1;

            private float textSizeRelative = DEFAULT_RELATIVE_TEXT_SIZE;

            private int style = Typeface.NORMAL;

            private boolean underline = false;

            private boolean strike = false;

            private boolean superscript = false;

            private boolean subscript = false;

            /**
             * Creates a new Builder for this Piece.
             * 
             * @param text the text of this Piece
             */
            public Builder(String text)
            {
                this.text = text;
            }

            /**
             * Sets the absolute text size.
             * 
             * @param textSize text size in pixels
             * @return a Builder
             */
            public Builder textSize(int textSize)
            {
                this.textSize = textSize;
                return this;
            }

            /**
             * Sets the text color.
             * 
             * @param textColor the color
             * @return a Builder
             */
            public Builder textColor(int textColor)
            {
                this.textColor = textColor;
                return this;
            }

            /**
             * Sets the background color.
             * 
             * @param backgroundColor the color
             * @return a Builder
             */
            public Builder backgroundColor(int backgroundColor)
            {
                this.backgroundColor = backgroundColor;
                return this;
            }

            /**
             * Sets the relative text size.
             * 
             * @param textSizeRelative relative text size
             * @return a Builder
             */
            public Builder textSizeRelative(float textSizeRelative)
            {
                this.textSizeRelative = textSizeRelative;
                return this;
            }

            /**
             * Sets a style to this Piece.
             * 
             * @param style see {@link android.graphics.Typeface}
             * @return a Builder
             */
            public Builder style(int style)
            {
                this.style = style;
                return this;
            }

            /**
             * Underlines this Piece.
             * 
             * @return a Builder
             */
            public Builder underline()
            {
                this.underline = true;
                return this;
            }

            /**
             * Strikes this Piece.
             * 
             * @return a Builder
             */
            public Builder strike()
            {
                this.strike = true;
                return this;
            }

            /**
             * Sets this Piece as a superscript.
             * 
             * @return a Builder
             */
            public Builder superscript()
            {
                this.superscript = true;
                return this;
            }

            /**
             * Sets this Piece as a subscript.
             * 
             * @return a Builder
             */
            public Builder subscript()
            {
                this.subscript = true;
                return this;
            }

            /**
             * Creates a {@link SpannableTextView.BabushkaText.Piece} with the customized parameters.
             * 
             * @return a Piece
             */
            public Piece build()
            {
                return new Piece(this);
            }
        }
    }

}


试着结合这个类Phrase.java那就更爽了;
ColorPhrase实现处理带颜色的字符串
https://github.com/THEONE10211024/ColorPhrase

https://github.com/quiqueqs/BabushkaText

Spanny实现字符串样式处理
https://github.com/binaryfork/Spanny
  • 大小: 8.6 KB
分享到:
评论

相关推荐

    SpannableTextView,.zip

    在Android开发中,TextView是用于展示文本的基本控件,而SpannableTextView则提供了一种更加高级的方式来控制文本的显示,允许开发者在不直接操作Spannable对象的情况下,实现文本片段的样式定制。 首先,Spannable...

    Android软件开发之TextView详解源码

    最后,对于自定义需求,开发者可以通过继承TextView并重写相关方法,或者使用装饰者模式,如创建一个自定义的Spannable来扩展TextView的功能。源码分析可以帮助我们了解何时何地插入自定义逻辑,从而实现独特的文本...

    TextView文字多种颜色,多种字号,不同颜色点击响应不同事件

    在Android开发中,`TextView` 是一个非常常用的控件,用于显示文本信息。在实际应用中,我们常常需要对`TextView`进行个性化设置,比如显示多种颜色、多种字号,甚至让不同颜色的文本具备不同的点击事件。这篇内容将...

    TextView控件学习

    在Android开发中,TextView是一个非常基础且重要的控件,它用于显示文本,是用户界面中不可或缺的部分。这篇教程将引导你从入门到深入地理解TextView的使用。 首先,TextView是Android SDK中的一个视图组件,它继承...

    TextView数字部分颜色处理

    `TextView`是Android SDK中的一个视图类,它允许我们显示单行或多行的文本。我们通常通过XML布局文件或代码动态创建并设置它的属性,如文本内容、字体大小、颜色等。 对于文本变色的需求,我们可以通过以下几种方式...

    android 更改TextView中任意位置字体大小和颜色的方法

    首先,需要在布局文件中添加一个 TextView控件: ```xml &lt;TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" /&gt; ``` 然后,在 Activity 中,使用 ...

    适用于长文本的TextView

    `TextView`是Android系统提供的一个基础组件,用于显示单行或多行文本。然而,当文本内容过长时,原生的`TextView`可能会面临一些挑战,比如滚动、换行处理不当等问题。为了更好地处理长文本,开发者通常会进行一些...

    textView属性

    本文将深入探讨`TextView`的各种属性及其应用,帮助开发者更好地理解和利用这个功能丰富的控件。 1. **文本内容** `TextView`的基础功能是显示文本,其文本内容可以通过`android:text`属性来设置。例如: ```xml ...

    TextView超链接自定义样式

    在Android开发中,`TextView` 是一个非常常用的控件,用于显示文本信息。然而,有时候我们需要在`TextView`中展示带有超链接的文本,让用户能够点击跳转到其他页面或执行特定操作。本篇将详细讲解如何在Android的`...

    Android TextView控件文字添加下划线的实现方法

    在Android开发中,TextView是用于显示文本的基本控件,它广泛应用于各种界面设计。有时候我们需要在TextView中的文字下方添加下划线,以突出显示某些文本或者作为超链接的标识。本文将详细介绍如何在Android中使用...

    RichTextView:一个基于Android原生TextView的富文本组件,解析Html格式的文本内容并进行显示

    总的来说,`RichTextView`是一个通过扩展Android原生`TextView`功能来实现富文本显示的组件,其核心在于HTML解析和Spannable的运用。通过理解和掌握这些知识点,开发者可以在自己的应用中轻松实现富文本展示,提高...

    Android 使用SpannableString在TextView中插入表情、超链接、文字变大、加粗Demo下载

    在Android开发中,文本展示是常见的需求之一,而TextView作为主要的文本展示控件,有时候我们需要在其中实现更丰富的展示效果,比如插入表情、添加超链接、改变文字大小和加粗等。本教程将深入讲解如何利用...

    Android设置TextView首行缩进示例代码

    在实现上,我们通过创建一个实现了LeadingMarginSpan2接口的匿名类对象,并将其应用到SpannableString对象上,最后将这个样式化的字符串设置给TextView显示。 总结来说,在Android中实现TextView首行缩进的推荐方法...

    android文字分页显示摇晃换页

    在这里,分页是针对文字内容进行的,意味着每个页面都包含一定数量的文字,可能是一个段落或者一个章节。 在描述中提到了"点击‘下一页’按钮"和"点击‘上一页’按钮",这表明应用使用了Button控件来触发页面切换。...

Global site tag (gtag.js) - Google Analytics