Android自定义View之文本变色

文章目录

      • 1. 概述
        • 1.1 缘由
        • 1.2 效果图
      • 2. 开撸
        • 2.1 分析
        • 2.2 自定义属性
        • 2.3 编写View
        • 2.4 测试
      • 3. 小结

1. 概述

1.1 缘由

在项目中,经常会遇到文字色值渐变效果,比如在ViewPage中的页面指示器,这种实现起来也比较简单,无非是计算偏移量、使用Paint以及Canvas提供的方法即可。

1.2 效果图

Android自定义View之文本变色_第1张图片

2. 开撸

2.1 分析

该文本有两种颜色,一种默认颜色,一种为要改变的颜色,因此需要两只画笔,根据偏移量,计算对应起始点、结束点使用相应画笔即可。

2.2 自定义属性

在这里,只简单定义三个属性

<declare-styleable name="ColorTrackTextView">
    <attr name="originColor" format="color" />
    <attr name="changeColor" format="color" />
    <attr name="direction" format="enum">
        <enum name="left2Right" value="1" />
        <enum name="right2Left" value="2" />
    attr>
declare-styleable>

2.3 编写View

根据分析,继承 TextView,重写onDraw方法即可。
详细注释见代码。

public class ColorTrackTextView extends TextView {

    private Paint mOriginPaint;
    private Paint mChangePaint;
    private float mProgress = 0.0f;

    private int mStartX = Integer.MIN_VALUE;
    private float mBaseLine = Float.MAX_VALUE;
    private Direction mDirection = Direction.LEFT2RIGHT;

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

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

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

    private void initPaint(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
        int originColor = typedArray.getColor(R.styleable.ColorTrackTextView_originColor, getTextColors().getDefaultColor());
        int changeColor = typedArray.getColor(R.styleable.ColorTrackTextView_changeColor, getTextColors().getDefaultColor());
        int index = typedArray.getInt(R.styleable.ColorTrackTextView_direction, -1);
        if (index >= 1) {
            setDirection(index);
        }
        mOriginPaint = getPaintByColor(originColor);
        mChangePaint = getPaintByColor(changeColor);
        typedArray.recycle();
    }

    private Paint getPaintByColor(int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setDither(true);
        paint.setTextSize(getTextSize());
        return paint;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int middle = (int) (mProgress * getWidth());
        // 从左到右
        if (mDirection == Direction.LEFT2RIGHT) {
            // 绘制变色区域
            drawText(canvas, mChangePaint, 0, middle);
            // 绘制不变色区域
            drawText(canvas, mOriginPaint, middle, getWidth());
        } else {// 从右到左
            // 绘制变色区域
            drawText(canvas, mChangePaint, getWidth() - middle, getWidth());
            // 绘制不变色区域
            drawText(canvas, mOriginPaint, 0, getWidth() - middle);
        }
    }

    /**
     * 绘制文本
     *
     * @param canvas
     * @param paint
     * @param start
     * @param end
     */
    private void drawText(Canvas canvas, Paint paint, int start, int end) {
        canvas.save();
        Rect rect = new Rect(start, 0, end, getHeight());
        canvas.clipRect(rect);
        canvas.drawText(getText().toString(), getStartX(paint), getBaseLine(paint), paint);
        canvas.restore();
    }

    /**
     * 计算文字开始X坐标
     *
     * @param paint
     * @return
     */
    private int getStartX(Paint paint) {
        if (mStartX != Integer.MIN_VALUE) return mStartX;
        String text = getText().toString();
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        mStartX = (getWidth() - bounds.width()) / 2;
        return mStartX;
    }

    /**
     * 计算baseLine
     *
     * @param paint
     * @return
     */
    private float getBaseLine(Paint paint) {
        if (mBaseLine != Float.MAX_VALUE) return mBaseLine;
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        mBaseLine = getHeight() / 2 + dy;
        return mBaseLine;
    }

    public void setDirection(Direction direction) {
        this.mDirection = direction;
    }

    public synchronized void setProgress(float progress) {
        if (progress < 0) {
            throw new IllegalArgumentException("进度不能小于0哦");
        }
        this.mProgress = progress;
        invalidate();
    }

    private void setDirection(int index) {
        if (index == 1) {
            mDirection = Direction.LEFT2RIGHT;
        } else if (index == 2) {
            mDirection = Direction.RIGHT2LEFT;
        }
    }

    public enum Direction {
        LEFT2RIGHT, RIGHT2LEFT
    }
}    

2.4 测试

验证下效果吧

测试Activity

class ColorTrackActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_color_track)
    }

    fun left2Right(view: View) {
        cttv_content.setDirection(ColorTrackTextView.Direction.LEFT2RIGHT)
        val anim = ObjectAnimator.ofFloat(0.0f, 1.0f)
        anim.duration = 5000
        anim.addUpdateListener { animation ->
            val progress = animation.animatedValue as Float
            cttv_content.setProgress(progress)
        }
        anim.start()
    }

    fun right2Left(view: View) {
        cttv_content.setDirection(ColorTrackTextView.Direction.RIGHT2LEFT)
        val anim = ObjectAnimator.ofFloat(0.0f, 1.0f)
        anim.duration = 5000
        anim.addUpdateListener { animation ->
            val progress = animation.animatedValue as Float
            cttv_content.setProgress(progress)
        }
        anim.start()
    }

}

activity_color_track布局文件:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <com.happy.android.study.view.ColorTrackTextView
        android:id="@+id/cttv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="小洋人最happy"
        android:textSize="28dp"
        app:changeColor="@android:color/holo_red_dark"
        app:direction="right2Left" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:orientation="horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="left2Right"
            android:text="从左到右渐变" />

        <Button
            android:id="@+id/right2Left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="right2Left"
            android:text="从右到左渐变" />

    LinearLayout>
LinearLayout>

3. 小结

实现代码比较简单,主要知识点如下:

  • Canvas.clipRect使用
  • 文本基准线计算
  • 偏移量计算

你可能感兴趣的:(android应用,android,自定义view,文本变色,canvas,paint)