红橙Darren视频笔记 一个控件显示两种颜色的文字 画笔的使用

本文介绍如何自定义一个Android View,实现在TextView中显示两种颜色的文字,并支持颜色从右到左或从左到右渐变,配合ViewPager切换。通过继承TextView并重写onDraw方法,以及定义自定义属性和动画,实现动态文本效果。
摘要由CSDN通过智能技术生成

需求分析

1.一行文字显示两种颜色
2.颜色变化可以从右到左或者从左到右
3.能够随着view pager切换
思路:
a.继承View:需要重写onMeasure onDraw方法
b.继承Text View 不需要重写onMeasure方法 只要重写onDraw方法
需要定义字体变化的颜色

效果

在这里插入图片描述

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- step1 定义组定义属性 -->
    <declare-styleable name="MultiColorTextView">
        <attr name="originColor" format="color"/>
        <attr name="changeColor" format="color"/>
    </declare-styleable>
</resources>

在xml中使用自定义属性

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:chjApp="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:padding="16dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.chj.muticolortextview.MultiColorTextView
        android:id="@+id/multi_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ccc"
        chjApp:originColor="#000"
        chjApp:changeColor="@color/colorAccent"
        android:textSize="20sp"
        android:text="Hello World!"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="leftToRight"
        android:onClick="leftToRight"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="rightToLeft"
        android:onClick="rightToLeft"/>

</LinearLayout>

编写自定义view

package com.example.chj.muticolortextview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;

@SuppressLint("AppCompatCustomView")
public class MultiColorTextView extends TextView {
    private Paint mOriginPaint;
    private Paint mChangePaint;
    //绘制进度
    private float mCurrentProgress = 0.0f;
    //绘制方向
    private Direction mCurrentDirection = Direction.LEFT_TO_RIGHT;

    public enum Direction {
        RIGHT_TO_LEFT, LEFT_TO_RIGHT
    }

    public MultiColorTextView(Context context) {
        this(context, null);
    }

    public MultiColorTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MultiColorTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint(context, attrs);
    }

    //1.1读取xml的自定义属性 初始化画笔
    private void initPaint(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MultiColorTextView);
        int originPaintColor = array.getColor(R.styleable.MultiColorTextView_originColor, Color.GREEN);
        int changePaintColor = array.getColor(R.styleable.MultiColorTextView_changeColor, Color.GREEN);
        mOriginPaint = getPaintByColor(originPaintColor);
        mChangePaint = getPaintByColor(changePaintColor);
        array.recycle();
    }

    private Paint getPaintByColor(int originPaintColor) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);//抗锯齿
        paint.setTextSize(getTextSize());//获取父类TextView定义的textSize
        paint.setDither(true);//防抖动
        paint.setColor(originPaintColor);
        return paint;
    }

    //2 实现一行文字两种颜色 思路 利用canvas.clipRect的api 不断裁切 坐标用一个画笔绘制 右边是另一个画笔绘制
    @Override
    protected void onDraw(Canvas canvas) {
        //不要使用TextView的onDraw方法
        //super.onDraw(canvas);


        //根据mCurrentProgress 计算两个画笔绘制的临界点
        int middle = (int) (getWidth() * mCurrentProgress);

//        //抽成方法start
//        //裁切区域 保留以下区域
//        //canvas.clipRect(0,0,80,getHeight());
//        canvas.save();
//        Rect rect = new Rect(0, 0, middle, getHeight());//裁剪区域 只绘制0-middle 左半区域
//        canvas.clipRect(rect);
//
//        //获取文字 计算位置 绘制文字
//        String text = getText().toString();
//        //获取text宽度
//        Rect bounds = new Rect();
//        mOriginPaint.getTextBounds(text, 0, text.length(), bounds);
//        //计算绘制origin的x坐标
//        int originStartX = (getWidth() - bounds.width()) / 2;
//
//        //计算绘制origin的y坐标(baseline)
//        Paint.FontMetrics fontMetrics = mOriginPaint.getFontMetrics();
//        float baseline = (getHeight()-fontMetrics.top-fontMetrics.bottom) / 2;
//        canvas.drawText(text, originStartX, baseline, mOriginPaint);
//        canvas.restore();//canvas.save();保存画布  canvas.restore();释放画布 如果不调用 无法进行再次裁切 他们成对调用
//
//        canvas.save();
//        rect = new Rect(middle, 0, getWidth(), getHeight());//裁剪区域 只绘制middle-getWidth 右半区域
//        canvas.clipRect(rect);
//        canvas.drawText(text, originStartX, baseline, mChangePaint);
//        canvas.restore();
//        //抽成方法end

        //将绘制左边和绘制右边的部分抽成一个方法 调用两次 与上面注释部分等价
        if (Direction.LEFT_TO_RIGHT == mCurrentDirection) {
            clipRectThenDrawText(canvas, mChangePaint, 0, middle);//只绘制0-middle 左半区域
            clipRectThenDrawText(canvas, mOriginPaint, middle, getWidth());//裁剪区域 只绘制middle-getWidth 右半区域
        } else {
            clipRectThenDrawText(canvas, mChangePaint, getWidth()-middle, getWidth());//只绘制右区域
            clipRectThenDrawText(canvas, mOriginPaint, 0, getWidth()-middle);//裁剪区域 只绘制左半区域
        }

    }

    private void clipRectThenDrawText(Canvas canvas, Paint paint, int startClip, int endClip) {
        canvas.save();
        Rect rect = new Rect(startClip, 0, endClip, getHeight());//裁剪区域 只绘制这个区域
        canvas.clipRect(rect);

        //获取文字 计算位置 绘制文字
        String text = getText().toString();
        //获取text宽度
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        //计算绘制origin的x坐标
        int originStartX = (getWidth() - bounds.width()) / 2;

        //计算绘制origin的y坐标(baseline)
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float baseline = (getHeight() - fontMetrics.top - fontMetrics.bottom) / 2;
        canvas.drawText(text, originStartX, baseline, paint);
        canvas.restore();//canvas.save();保存画布  canvas.restore();释放画布 如果不调用 无法进行再次裁切 他们成对调用
    }

    public void setCurrentProgress(float mCurrentProgress) {
        this.mCurrentProgress = mCurrentProgress;
        invalidate();
    }

    public void setCurrentDirection(Direction direction) {
        this.mCurrentDirection = direction;
    }
}


编写测试代码

package com.example.chj.muticolortextview;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private MultiColorTextView multiColorTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        multiColorTextView = findViewById(R.id.multi_tv);
    }

    public void leftToRight(View view) {
        multiColorTextView.setCurrentDirection(MultiColorTextView.Direction.LEFT_TO_RIGHT);
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0,1);
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float mCurrentProgress = (float) animation.getAnimatedValue();
                multiColorTextView.setCurrentProgress(mCurrentProgress);
            }
        });
        valueAnimator.start();
    }

    public void rightToLeft(View view) {
        multiColorTextView.setCurrentDirection(MultiColorTextView.Direction.RIGHT_TO_LEFT);
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0,1);
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float mCurrentProgress = (float) animation.getAnimatedValue();
                multiColorTextView.setCurrentProgress(mCurrentProgress);
            }
        });
        valueAnimator.start();
    }
}

源码:
https://github.com/caihuijian/learn_darren_android.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值