自定义View继承自TextView。三部曲:onMeasure()\onDraw()\onTouch()
1.思路分析
1.1.思路:
实现字体变色大前提实现Text,而android已经实现过了---TextView。那么我们在实现自己功能的时候可以采用直接继承TextView的方法。这样textColor等属性就可以不用在自定义,同时onMeasure()\onTouch()也不用重写,减少代码逻辑。
1.2.变色
a.一个字体有两种颜色
b.能够从左到右,从右到左。
c.整合到ViewPager。
自定义属性:变化的颜色和不变化的颜色
2.字体颜色
自定义属性:attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextTrack">
<attr name="originColor" format="color"/>
<attr name="changeColor" format="color"/>
</declare-styleable>
</resources>
使用属性:avtivity_main.xml
<com.example.textcolor.TextTrack
android:id="@+id/textTrack"
android:layout_width="312dp"
android:layout_height="171dp"
android:text="Hello World"
app:changeColor="@color/black"
app:originColor="@color/design_default_color_primary" />
3.自定义View--初始化、获取画笔、绘制、实现不同朝向
View:TextTrack.java
3.1.初始化、画笔
public TextTrack(Context context) {
this(context,null);
}
public TextTrack(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public TextTrack(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextTrack);
int originColor = typedArray.getColor(R.styleable.TextTrack_originColor,getTextColors().getDefaultColor());
int changeColor = typedArray.getColor(R.styleable.TextTrack_changeColor,getTextColors().getDefaultColor());
typedArray.recycle();
originPaint = new Paint();
originPaint.setColor(originColor);//设置颜色
originPaint.setAntiAlias(true);//抗锯齿
originPaint.setDither(true);//防抖动
originPaint.setTextSize(getTextSize());
changePaint = new Paint();
changePaint.setColor(changeColor);//设置颜色
changePaint.setAntiAlias(true);//抗锯齿
changePaint.setDither(true);//防抖动
changePaint.setTextSize(getTextSize());
}
3.2 绘制
@Override
protected void onDraw(Canvas canvas) {
//自己画文字
//canves有一个裁剪的api,利用该方法,左边用一个颜色,右边有一个颜色,不断的改变中间值:根据进度算中间值
int middle = (int) (mCurrentProgress * getWidth());
//绘制不变色的
if (direction == Direction.LEFT_TO_RIGHT) {
canvas.save();//保存画布
Rect rect = new Rect(0, 0, middle, getHeight());
canvas.clipRect(rect);
String text = getText().toString();
Rect bounds = new Rect();
originPaint.getTextBounds(text, 0, text.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
//基线
Paint.FontMetrics fontMetrics = changePaint.getFontMetrics();
int dy = (int) ((int) ((fontMetrics.bottom - fontMetrics.top)) / 2 - fontMetrics.bottom);
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, originPaint);//此时还是一种颜色
canvas.restore();//释放画布
canvas.save();
rect = new Rect(getWidth(), 0, getWidth()-middle, getHeight());
canvas.clipRect(rect);
canvas.drawText(text, x, baseLine, changePaint);
Log.d("TAG", "" + changePaint.getColor());
canvas.restore();
}else {
canvas.save();//保存画布
Rect rect = new Rect(getWidth()-middle, 0, getWidth(), getHeight());
canvas.clipRect(rect);
String text = getText().toString();
Rect bounds = new Rect();
originPaint.getTextBounds(text, 0, text.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
//基线
Paint.FontMetrics fontMetrics = changePaint.getFontMetrics();
int dy = (int) ((int) ((fontMetrics.bottom - fontMetrics.top)) / 2 - fontMetrics.bottom);
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, originPaint);//此时还是一种颜色
canvas.restore();//释放画布
canvas.save();
rect = new Rect(0, 0, middle, getHeight());
canvas.clipRect(rect);
canvas.drawText(text, x, baseLine, changePaint);
Log.d("TAG", "" + changePaint.getColor());
canvas.restore();
}
}
3.3.不同朝向--LEFT_TO_RIGHT\RIGHT_TO_LEFT
定义一个枚举:方向。默认:从右向左
private Direction direction = Direction.RIGHT_TO_LEFT;
//实现不同的朝向,定义一个枚举变量
public enum Direction{
LEFT_TO_RIGHT,RIGHT_TO_LEFT;
}
设置方向
public void setmCurrentProgress(float mCurrentProgress) {
this.mCurrentProgress = mCurrentProgress;
}
public void setDirection(Direction direction) {
this.direction = direction;
invalidate();
}
4.main函数
package com.example.textcolor;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private TextTrack textTrack;
private Button left,right;
// private int mCurrentProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textTrack = findViewById(R.id.textTrack);
left = findViewById(R.id.left);
right = findViewById(R.id.right);
left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ValueAnimator objectAnimator = ValueAnimator.ofFloat(0,1);
objectAnimator.setDuration(10000);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float mCurrentProgress = (float) objectAnimator.getAnimatedValue();
textTrack.setmCurrentProgress(mCurrentProgress);
textTrack.setDirection(TextTrack.Direction.LEFT_TO_RIGHT);
}
});
objectAnimator.start();
}
});
right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ValueAnimator objectAnimator = ValueAnimator.ofFloat(0,1);
objectAnimator.setDuration(10000);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float mCurrentProgress = (float) objectAnimator.getAnimatedValue();
textTrack.setmCurrentProgress(mCurrentProgress);
textTrack.setDirection(TextTrack.Direction.RIGHT_TO_LEFT);
}
});
objectAnimator.start();
}
});
}
}
5.附件
package com.example.textcolor;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.Nullable;
public class TextTrack extends androidx.appcompat.widget.AppCompatTextView {
private Paint originPaint,changePaint;
//实现一个文字两种颜色,当前的进度
private float mCurrentProgress = 0.5f;
private Direction direction = Direction.RIGHT_TO_LEFT;
//实现不同的朝向,定义一个枚举变量
public enum Direction{
LEFT_TO_RIGHT,RIGHT_TO_LEFT;
}
public TextTrack(Context context) {
this(context,null);
}
public TextTrack(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public TextTrack(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextTrack);
int originColor = typedArray.getColor(R.styleable.TextTrack_originColor,getTextColors().getDefaultColor());
int changeColor = typedArray.getColor(R.styleable.TextTrack_changeColor,getTextColors().getDefaultColor());
typedArray.recycle();
originPaint = new Paint();
originPaint.setColor(originColor);//设置颜色
originPaint.setAntiAlias(true);//抗锯齿
originPaint.setDither(true);//防抖动
originPaint.setTextSize(getTextSize());
changePaint = new Paint();
changePaint.setColor(changeColor);//设置颜色
changePaint.setAntiAlias(true);//抗锯齿
changePaint.setDither(true);//防抖动
changePaint.setTextSize(getTextSize());
}
@Override
protected void onDraw(Canvas canvas) {
//自己画文字
//canves有一个裁剪的api,利用该方法,左边用一个颜色,右边有一个颜色,不断的改变中间值:根据进度算中间值
int middle = (int) (mCurrentProgress * getWidth());
//绘制不变色的
if (direction == Direction.LEFT_TO_RIGHT) {
canvas.save();//保存画布
Rect rect = new Rect(0, 0, middle, getHeight());
canvas.clipRect(rect);
String text = getText().toString();
Rect bounds = new Rect();
originPaint.getTextBounds(text, 0, text.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
//基线
Paint.FontMetrics fontMetrics = changePaint.getFontMetrics();
int dy = (int) ((int) ((fontMetrics.bottom - fontMetrics.top)) / 2 - fontMetrics.bottom);
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, originPaint);//此时还是一种颜色
canvas.restore();//释放画布
canvas.save();
rect = new Rect(getWidth(), 0, getWidth()-middle, getHeight());
canvas.clipRect(rect);
canvas.drawText(text, x, baseLine, changePaint);
Log.d("TAG", "" + changePaint.getColor());
canvas.restore();
}else {
canvas.save();//保存画布
Rect rect = new Rect(getWidth()-middle, 0, getWidth(), getHeight());
canvas.clipRect(rect);
String text = getText().toString();
Rect bounds = new Rect();
originPaint.getTextBounds(text, 0, text.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
//基线
Paint.FontMetrics fontMetrics = changePaint.getFontMetrics();
int dy = (int) ((int) ((fontMetrics.bottom - fontMetrics.top)) / 2 - fontMetrics.bottom);
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, originPaint);//此时还是一种颜色
canvas.restore();//释放画布
canvas.save();
rect = new Rect(0, 0, middle, getHeight());
canvas.clipRect(rect);
canvas.drawText(text, x, baseLine, changePaint);
Log.d("TAG", "" + changePaint.getColor());
canvas.restore();
}
}
public void setmCurrentProgress(float mCurrentProgress) {
this.mCurrentProgress = mCurrentProgress;
}
public void setDirection(Direction direction) {
this.direction = direction;
invalidate();
}
}
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.textcolor.TextTrack
android:id="@+id/textTrack"
android:layout_width="312dp"
android:layout_height="171dp"
android:text="Hello World"
app:changeColor="@color/black"
app:originColor="@color/design_default_color_primary" />
<Button
android:id="@+id/left"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="left_to_right"/>
<Button
android:id="@+id/right"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="right_to_left"/>
</LinearLayout>