1.分解步骤
- 1.分析效果
- 2.确定自定义属性,编写attrs.xml
- 3.在布局中使用
- 4.编写自定义控件实现类
- 5.定义并初始化所需变量(如文字画笔,颜色进度占比等)
- 5.ondraw()画文字,编写绘制逻辑(主要运用到“切割画板”的思想)
- 6.其他处理(动画效果)
2.具体步骤
- 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>
<?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.incall.apps.textswitch.ColorTrackTextView
android:id="@+id/text_draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="32sp"
android:layout_gravity="center"
app:originColor="@color/black"
app:changeColor="@color/teal_200"
android:text="Hello World !!"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左到右"
android:layout_gravity="center"
android:onClick="leftToRight"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右到右"
android:layout_gravity="center"
android:onClick="rightToLeft"/>
</LinearLayout>
- 编写控件类ColorTrackTextView,继承textView
package com.incall.apps.textswitch;
import android.annotation.SuppressLint;
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.widget.TextView;
import androidx.annotation.Nullable;
@SuppressLint("AppCompatCustomView")
public class ColorTrackTextView extends TextView {
private Paint mOriginPaint; //初始颜色画笔
private Paint mChangePaint; //变化颜色画笔
//设置变色百分比
private float currentProgress = 0.0f;
//设置变色朝向
Direction mdirection = Direction.LEFT_TO_RIGHT;
enum Direction {
LEFT_TO_RIGHT, RIGHT_TO_LEFT;
}
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) {
this(context, attrs, defStyleAttr, 0);
}
public ColorTrackTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initPaint(context, attrs);
}
/**
* 初始化
*/
private void initPaint(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
int orginColor = array.getColor(R.styleable.ColorTrackTextView_originColor, getTextColors().getDefaultColor());
int changeColor = array.getColor(R.styleable.ColorTrackTextView_changeColor, getTextColors().getDefaultColor());
mOriginPaint = getPaintByColor(orginColor);
mChangePaint = getPaintByColor(changeColor);
array.recycle();
}
/**
* 根据颜色值获取画笔
*
* @return
*/
private Paint getPaintByColor(int color) {
Paint paint = new Paint();
//设置颜色
paint.setColor(color);
//抗锯齿
paint.setAntiAlias(true);
//防抖动
paint.setDither(true);
//设置字体大小
paint.setTextSize(getTextSize());
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
int middle = (int) (currentProgress * getWidth());
//从左变到右
if (mdirection == Direction.LEFT_TO_RIGHT) {
drawText(canvas, mOriginPaint, middle, getWidth());
drawText(canvas, mChangePaint, 0, middle);
}
//从右边变到左
else if (mdirection == Direction.RIGHT_TO_LEFT) {
drawText(canvas, mOriginPaint, 0, getWidth() - middle);
drawText(canvas, mChangePaint, getWidth() - middle, getWidth());
}
}
/**
* * @description 文字图像绘制
* @param canvas
* @param paint
* @param start
* @param end
* @return void
*/
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();
//计算起始位置
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int x = getWidth() / 2 - bounds.width() / 2;
//计算基线
Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, paint);
canvas.restore();//释放画板
}
public void setCurrentProgress(float currentProgress) {
this.currentProgress = currentProgress;
invalidate();
}
public void setMdirection(Direction mdirection) {
this.mdirection = mdirection;
}
}
- 编写MainActivity,添加属性动画,添加按钮逻辑
package com.incall.apps.textswitch;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
ColorTrackTextView textDraw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textDraw = findViewById(R.id.text_draw);
}
public void leftToRight(View view) {
textDraw.setMdirection(ColorTrackTextView.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 currentProgress = (Float) animation.getAnimatedValue();
textDraw.setCurrentProgress(currentProgress);
}
});
valueAnimator.start();
}
public void rightToLeft(View view) {
textDraw.setMdirection(ColorTrackTextView.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 currentProgress = (Float) animation.getAnimatedValue();
textDraw.setCurrentProgress(currentProgress);
}
});
valueAnimator.start();
}
}
3.效果图