这个控件本人强烈推荐,它会使得布局非常的简单且高效;
下面这个布局如果是你,你会用多少层?多少控件生成?
告诉你吧,一个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, "血糖 ", "记录血糖指数");
- tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView1));
- context.createSpannableTextView(tv, "血压 ", "记录血压指数");
- tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView2));
- context.createSpannableTextView(tv, "体重 ", "记录体重");
- tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView3));
- context.createSpannableTextView(tv, "饮食 ", "记录日常饮食");
- tv = (SpannableTextView) (v.findViewById(R.id.spannableTextView4));
- context.createSpannableTextView(tv, "运动 ", "记录运动时间");
- <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 "Central Park"
- * tv.addPiece(new SpannableTextView.Piece.Builder("Central Park, NY ").textColor(Color.parseColor("#414141")).build());
- *
- * // Add the second piece "1.2 mi"
- * tv.addPiece(new SpannableTextView.Piece.Builder("1.2 mi ").textColor(Color.parseColor("#0081E2")).textSizeRelative(0.9f).build());
- *
- * // Add the third piece "from here"
- * tv.addPiece(new SpannableTextView.Piece.Builder("from here").textColor(Color.parseColor("#969696")).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("1.9 km ");
- *
- * // 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