美文网首页
Android 自定义文字变色

Android 自定义文字变色

作者: 我要离开浪浪山 | 来源:发表于2023-04-16 23:02 被阅读0次

1、ViewGroup为什么不会执行onDraw?

  • 1、View.draw(是DecorView);
  • 2、View.java类中,调用onDraw(canvas)和dispatchDraw(canvas);
  • 3、dispatchDraw(canvas)其实调用的是ViewGroup.dispatchDraw();
  • 4、ViewGroup.dispatchDraw()里面会执行drawChild(canvas,child,drawingTime);
  • 5、View.java类中,进入drawChild()里面,会中View.draw()三个参数的方法();
  • 6、View.java类中,会调用updateDisplayListIfDirty()->dispatchDraw(canvas);

2、文字变色

需求:类似播放音乐文字变色功能

效果图.png

1、自定义文字变色步骤

  • 1.自定义属性,以及xml中使用
  • 2.测量 --- 只需要测量自己
  • 3.onDraw:绘制自己
  • 4.交互

2、调用MainActivity

public class MainActivity extends AppCompatActivity {

    private ColorTrackTextView mColorTrackTextView;

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

    public void leftToRight(View view) {
        setAnimation(ColorTrackTextView.Direction.LEFT_TO_RIGHT);
    }

    public void rightToLeft(View view) {
        setAnimation(ColorTrackTextView.Direction.RIGHT_TO_LEFT);
    }

    public void setAnimation(ColorTrackTextView.Direction direction) {
        mColorTrackTextView.setDirection(direction);
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentProgress = (float) animation.getAnimatedValue();
                mColorTrackTextView.setCurrentProgress(currentProgress);
            }
        });
        valueAnimator.start();
    }

3、activity_main.xml

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

    <com.leo.colortrackview.ColorTrackTextView
        android:id="@+id/color_track_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="20sp"
        app:changeColor="@color/teal_200" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="leftToRight"
        android:text="左到右" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="rightToLeft"
        android:text="右到左" />
</LinearLayout>

4、ColorTrackTextView

package com.leo.colortrackview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

public class ColorTrackTextView extends AppCompatTextView {

    // 绘制不变色字体的画笔
    private Paint mOriginPaint;
    // 绘制变色字体的画笔
    private Paint mChangePaint;
    // 当前变色的进度
    private float mCurrentProgress = 0.5f;

    // 实现不同朝向
    private Direction mDirection;

    public enum Direction {
        LEFT_TO_RIGHT, RIGHT_TO_LEFT
    }

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

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

    public ColorTrackTextView(@NonNull 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());

        // 回收
        typedArray.recycle();

        // 不变色的画笔
        mOriginPaint = getPaintByColor(originColor);
        // 变色的画笔
        mChangePaint = getPaintByColor(changeColor);
    }

    /**
     * 根据颜色获取画笔
     */
    private Paint getPaintByColor(int color) {
        Paint paint = new Paint();
        // 设置颜色
        paint.setColor(color);
        // 设置抗锯齿
        paint.setAntiAlias(true);
        // 防抖动
        paint.setDither(true);
        // 设置字体的大小  就是TextView的字体大小
        paint.setTextSize(getTextSize());
        return paint;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int currentPoint = (int) (mCurrentProgress * getWidth());

        // 从左边到右边变色
        if (mDirection == Direction.LEFT_TO_RIGHT) {
            // 绘制变色的部分 -- 开始 currentPoint = 0;结束 currentPoint = getWidth
            drawText(canvas, mChangePaint, 0, currentPoint);
            // 绘制不变色的部分
            drawText(canvas, mOriginPaint, currentPoint, getWidth());
        } else {
            // 绘制变色的部分 -- 开始 currentPoint = getWidth;结束 currentPoint = 0
            drawText(canvas, mChangePaint, getWidth() - currentPoint, getWidth());
            // 绘制不变色的部分
            drawText(canvas, mOriginPaint, 0, getWidth() - currentPoint);
        }
    }


    private void drawText(Canvas canvas, Paint paint, int start, int end) {
        canvas.save();
        Rect rect = new Rect(start, 0, end, getHeight());
        canvas.clipRect(rect);

        String text = getText().toString();
        // 判空
        if (TextUtils.isEmpty(text)) return;

        // 获取文字的区域
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        // 获取x坐标
        int dx = getWidth() / 2 - bounds.width() / 2;
        // 获取基线  baseLine
        Paint.FontMetricsInt fontMetricsInt = mChangePaint.getFontMetricsInt();
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        int baseLine = getHeight() / 2 + dy;

        // 绘制文字
        canvas.drawText(text, dx, baseLine, paint);
        canvas.restore();
    }

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

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

}
获取基线.png

5、attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorTrackTextView">
        <attr name="originColor" format="color" />
        <attr name="changeColor" format="color" />
    </declare-styleable>
</resources>
fb1b582f250bc4ac53f7a669e7ef2b8.png

3、自定义FlowLayout

1、FlowLayout

package com.leo.flowlayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

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

public class FlowLayout extends ViewGroup {

    private List<View> mLineViews;//每一行的子View
    private List<List<View>> mViews;//所有的行 一行一行的存储
    private List<Integer> mHeights;//每一行的高度

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

    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    private void init() {
        mLineViews = new ArrayList<>();
        mViews = new ArrayList<>();
        mHeights = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 获取限制的值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 记录当前行的宽度和高度
        int lineWidth = 0;// 宽度是当前行子view的宽度之和
        int lineHeight = 0;// 高度是当前行所有子View中高度的最大值

        //整个流式布局的宽度和高度
        int flowLayoutWidth = 0;//所有行中宽度的最大值
        int flowLayoutHeight = 0;// 所以行的高度的累加

        init();

        int childCount = this.getChildCount();

        // 先测量子View,再根据子View尺寸,计算自己的
        for (int i = 0; i < childCount; i++) {
            View child = this.getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);

            //获取到当前子View的测量的宽度/高度
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 已经放入的孩子的宽度 + 准备放入的孩子的宽度 大于 总宽度 就换行
            if (lineWidth + childWidth > widthSize) {
                mViews.add(mLineViews);
                mLineViews = new ArrayList<>();//创建新的一行
                // 所有行中 最宽的一行 作为 流式布局的宽
                flowLayoutWidth = Math.max(flowLayoutWidth, lineWidth);
                // 流式布局的高度为所有行的高度相加
                flowLayoutHeight += lineHeight;
                mHeights.add(lineHeight);
                lineWidth = 0;
                lineHeight = 0;
            }

            mLineViews.add(child);
            lineWidth += childWidth;

            // 获取行中最高的子View
            lineHeight = Math.max(lineHeight, childHeight);
        }

        // 保存尺寸给后面用
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : flowLayoutWidth
                , heightMode == MeasureSpec.EXACTLY ? heightSize : flowLayoutHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int currX = 0;
        int currY = 0;
        int lineCount = mViews.size();
        // 处理每一行
        for (int i = 0; i < lineCount; i++) {
            List<View> lineViews = mViews.get(i);
            int lineHeight = mHeights.get(i);
            int size = lineViews.size();
            // 处理每一行中的View
            for (int j = 0; j < size; j++) {
                View child = lineViews.get(j);
                // 子View的左上右下
                int left = currX;
                int top = currY;
                int right = left + child.getMeasuredWidth();
                int bottom = top + child.getMeasuredHeight();
                // 布局子View
                child.layout(left, top, right, bottom);
                currX += child.getMeasuredWidth();
            }
            currY += lineHeight;
            currX = 0;
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.leo.flowlayout.FlowLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/mFlowLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="55dp"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:text="一行一个元素生活不止眼前的苟且,还有诗和远方大法师的打分sad发送到发送到发的发送到发送到第三方阿萨德佛挡杀佛但是" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="11一行一个元素生活不止眼前的苟且,还有诗和远方大法师的打分sad发送到发送到发的发送到发送到第三方阿萨德佛挡杀佛但是" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="85dp"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="45dp"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="75dp"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="85dp"
            android:text="小麻小儿郎呀" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="85dp"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="85dp"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="65dp"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="75dp"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />


        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="300dp"
            android:text="生活不止眼前的苟且,还有诗和远方" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="小麻小儿郎呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello hi ..." />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="你是谁呀" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="65dp"
            android:layout_gravity="bottom"
            android:text="人在他在,塔亡人亡" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="生活不止眼前的苟且,还有诗和远方1" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="250dp"
            android:text="发电房" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="这是结束" />
    </com.leo.flowlayout.FlowLayout>

</ScrollView>

相关文章

网友评论

      本文标题:Android 自定义文字变色

      本文链接:https://www.haomeiwen.com/subject/pryqjdtx.html