如果我们要改变 TextView 中某一个字 ,或者某一段字的颜色,那样会非常麻烦,虽然可以使用别的方法改变颜色。但是如何你的 TextView 只是需要展示一下,不需要绑定控件等,使用那种方法就会非常麻烦,下面我们自定义一个CustomTextView来实现这种效果。
1,修改单个字的颜色
2,修改多个字的颜色
3,可是设置多种颜色
4,可指定某个字的颜色
5,批量设置,每个字对应一种颜色
1,指定需要的属性
在 res/values 下创建 attrs.xml 文件
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 自定义View的名字 --> <declare-styleable name="CustomTextView"> <declare-styleable name="CustomTextView"> <!-- 文字-string --> <attr name="text" format="string" /> <!-- 文字大小-dimension --> <attr name="textSize" format="dimension" /> <!-- 文字颜色-color--> <attr name="textColor" format="color" /> <!--指定位置的颜色--> <attr name="tvColor" format="color" /> <!--要改变颜色的文字--> <attr name="tv" format="string" /> <!--指定位置--> <attr name="startPosInteger" format="integer" /> <attr name="endPosInteger" format="integer" /> </declare-styleable> </resources>
2,自定义View
public class CustomTextView extends AppCompatTextView { /** * 要显示文字 */ private String mText; /** * 要改变颜色的文字 */ private String mTv = null; /** * 文字默认大小 15sp */ private int mTextSize = 15; /** * 文字默认颜色 */ private int mTextColor = Color.BLACK; /** * 需要改变的颜色 */ private int mTvColor = Color.RED; /** * 画笔 */ private TextPaint mPaint; private Rect wRect; private Rect hRect; private int startPos = -1; private int endPos = -1; private String[] mTvs = null; private Integer[] mColors = null; /** * 这种调用第1个构造方法 * TextView tv = new TextView(this): */ public CustomTextView(Context context) { this(context, null); } /** * 这种调用第2个构造方法 * <com.novate.test.customview.MyTextView * ......> */ public CustomTextView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 获取自定义属性 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView); // 获取文字 mText = typedArray.getString(R.styleable.CustomTextView_text); //获取设置颜色的文字 mTv = typedArray.getString(R.styleable.CustomTextView_tv); // 获取文字大小 mTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomTextView_textSize, sp2px(mTextSize)); // 获取文字颜色 typedArray.getColor(R.styleable.CustomTextView_textColor, mTextColor); startPos = typedArray.getInt(R.styleable.CustomTextView_startPosInteger, -1); endPos = typedArray.getInt(R.styleable.CustomTextView_endPosInteger, -1); mTvColor = typedArray.getInt(R.styleable.CustomTextView_tvColor, Color.RED); // 释放资源 typedArray.recycle(); // 创建画笔 mPaint = new TextPaint(); // 设置抗锯齿,让文字比较清晰,同时文字也会变得圆滑 mPaint.setAntiAlias(true); // 设置文字大小 mPaint.setTextSize(mTextSize); // 设置画笔颜色 mPaint.setColor(mTextColor); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 如果在布局文件中设置的宽高都是固定值[比如100dp、200dp等],就用下边方式直接获取宽高 int width = View.MeasureSpec.getSize(widthMeasureSpec); int height = View.MeasureSpec.getSize(heightMeasureSpec); int widthMode = View.MeasureSpec.getMode(widthMeasureSpec); int heightMode = View.MeasureSpec.getMode(heightMeasureSpec); // 如果在布局中设置宽高都是wrap_content[对应AT_MOST],必须用mode计算 if (widthMode != MeasureSpec.EXACTLY) { // 文字宽度 与字体大小和长度有关 if (wRect == null) { wRect = new Rect(); } // 获取文本区域 param1__测量的文字 param2__从位置0开始 param3__到文字长度 mPaint.getTextBounds(mText, 0, mText.length(), wRect); // 文字宽度 getPaddingLeft宽度 getPaddingRight高度 写这两个原因是为了在布局文件中设置padding属性起作用 width = wRect.width() + getPaddingLeft() + getPaddingRight(); } if (hRect == null) { hRect = new Rect(); } if (heightMode != MeasureSpec.EXACTLY) { mPaint.getTextBounds(mText, 0, mText.length(), hRect); height = hRect.height() + getPaddingTop() + getPaddingBottom(); } // 给文字设置宽高 setMeasuredDimension(width, height); } /** * 绘制文字 */ @Override protected void onDraw(Canvas canvas) { if (mTv != null && !mTv.isEmpty()) { int start = mText.indexOf(mTv); int end = start + mTv.length(); startToEnd(canvas, start, end, mTvColor); } else if (mTvs != null) { if (mColors != null && mColors.length == mTvs.length) { sort(); drawTvs(Arrays.asList(mTvs), Arrays.asList(mColors), canvas); } else { drawTvs(Arrays.asList(mTvs), canvas); } } else if (startPos > -1 && endPos > -1) { startToEnd(canvas, startPos, endPos, mTvColor); } else if (startPos > -1) { startToEnd(canvas, startPos, startPos + 1, mTvColor); } else { int baseLine = getBaseLine(); mPaint.setColor(mTextColor); canvas.drawText(mText, getPaddingLeft(), baseLine, mPaint); } } /** * 指定位置的文字变为指定的颜色 * * @param canvas 画布 * @param startPos 开始的位置 * @param endPos 结束的位置 * @param colorPos 指定的颜色 */ private void startToEnd(Canvas canvas, int startPos, int endPos, int colorPos) { if (startPos <= -1 && endPos <= -1) { throw new IndexOutOfBoundsException("索引异常,检查需要修改的文字是否设置正确"); } int baseLine = getBaseLine(); int paddingLeft = getPaddingLeft(); String start = mText.substring(0, startPos); String red = mText.substring(startPos, endPos); String end = mText.substring(endPos, mText.length()); canvas.drawText(start, paddingLeft, baseLine, mPaint); mPaint.setColor(colorPos); float redLength = Layout.getDesiredWidth(start, mPaint) + paddingLeft; canvas.drawText(red, redLength, baseLine, mPaint); mPaint.setColor(mTextColor); float endLength = Layout.getDesiredWidth(red, mPaint) + Layout.getDesiredWidth(start, mPaint) + paddingLeft; canvas.drawText(end, endLength, baseLine, mPaint); } private void drawTvs(List<String> tvs, Canvas canvas) { mColors = new Integer[mTvs.length]; for (int i = 0; i < mColors.length; i++) { mColors[i] = mTvColor; } drawTvs(tvs, Arrays.asList(mColors), canvas); } private void drawTvs(List<String> tvs, List<Integer> colors, Canvas canvas) { int baseLine = getBaseLine(); int paddingLeft = getPaddingLeft(); for (int i = 0; i < tvs.size(); i++) { int start = mText.indexOf(tvs.get(i)); int end = start + tvs.get(i).length(); String startPos = mText.substring(0, start); String redPos = mText.substring(start, end); String endPos; if (tvs.size() > i + 1) { endPos = mText.substring(end, mText.indexOf(tvs.get(i + 1))); } else { endPos = mText.substring(end, mText.length()); } if (i == 0) { canvas.drawText(startPos, paddingLeft, baseLine, mPaint); } if (mColors != null && colors.size() > i) { mPaint.setColor(colors.get(i)); } else { mPaint.setColor(mTvColor); } float redLength = Layout.getDesiredWidth(startPos, mPaint) + paddingLeft; canvas.drawText(redPos, redLength, baseLine, mPaint); mPaint.setColor(mTextColor); float endLength = Layout.getDesiredWidth(redPos, mPaint) + Layout.getDesiredWidth(startPos, mPaint) + paddingLeft; canvas.drawText(endPos, endLength, baseLine, mPaint); } } /** * 开始的位置,可单独使用 * * @param startPos 开始的位置,未设置结束位置则结束位置为 startPos + 1 */ public void startPos(int startPos) { this.startPos = startPos; } /** * 结束位置 * * @param endPos 结束位置,必须大于开始位置 */ public void endPos(int endPos) { this.endPos = endPos; } /** * 设置要改变颜色的文字,和设置 位置 选择其一即可 * * @param colorText 改变颜色的文字 */ public void setColorTv(String colorText) { this.mTv = colorText; } /** * 多个地方的颜色需要修改可以使用此方法 * * @param tvs 需要修改的文字数组 */ public void setTvs(String[] tvs) { this.mTvs = tvs; } public void setTvs(String[] tvs, Integer[] colors) { this.mTvs = tvs; this.mColors = colors; } /** * 设置普通文字的颜色 * * @param color 颜色 */ public void setTextColor(@ColorInt int color) { this.mTextColor = color; } /** * 设置要文字需要改变的颜色 * * @param color */ public void setTvColor(@ColorInt int color) { this.mTvColor = color; } /** * 设置 text * * @param mText text */ public void setText(String mText) { this.mText = mText; } public void setTv(String changeTxt) { this.mTv = changeTxt; } /** * 设置默认文本颜色 * * @param mTextSize size */ public void setTestSize(int mTextSize) { this.mTextSize = mTextSize; } public void notifyTv() { invalidate(); } /** * 获取基线 */ private int getBaseLine() { Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt(); int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom; return getHeight() / 2 + dy; } /** * sp转为px */ private int sp2px(int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } private void sort() { for (int i = 0; i < mTvs.length; i++) { for (int j = i + 1; j < mTvs.length; j++) { if (mText.indexOf(mTvs[i]) > mText.indexOf(mTvs[j])) { String text = mTvs[i]; mTvs[i] = mTvs[j]; mTvs[j] = text; int color = mColors[i]; mColors[i] = mColors[j]; mColors[j] = color; } } } } }
注释都写在上面 了,下面看一下使用
3,使用
先看一下最普通的使用:
<com.business.tools.views.CustomTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" app:text="姓名*:张三" app:textColor="#000000" app:textSize="25sp" />
设置指定文字的颜色
<com.business.tools.views.CustomTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" app:text="姓名*:张三" app:textColor="#000000" app:textSize="25sp" app:tv="*" app:tvColor="#ff0000"
使用
tv 来指定 修改的文字,tvColor 指定修改文字的颜色。默认是红色
设置某一段文字的颜色
<com.business.tools.views.CustomTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" app:endPosInteger="6" app:startPosInteger="4" app:text="姓名*:张三" app:textColor="#000000" app:textSize="25sp" />
设置指定文字的颜色
<com.business.tools.views.CustomTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" app:endPosInteger="6" app:startPosInteger="4" app:text="姓名*:张三" app:textColor="#000000" app:textSize="25sp" app:tvColor="#FF110BC9"/>
指定多个字的颜色
<com.business.tools.views.CustomTextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" /> CustomTextView textView = findViewById(R.id.tv); textView.setText("Android-EasyTools" + "一个通用的业务代码解决方案"); textView.setTvs(new String[]{"Android-EasyTools", "通用", "解决方案"}, new Integer[]{Color.BLUE, Color.GREEN, Color.CYAN}); textView.notifyTv();
注意:最后要使用 notifyTv 刷新,
注意:不支持换行
在 xml 中可以定义的属性在代码中也可以同样定义
以上就是具体的使用了,如果需要什么功能,直接在 CustomTextView 中添加就行了。如有错误,还请指出