首先,分析上面的动态图,其中两个不同的textview,一个颜色是从左往右变化的,另一个是从右往左变化的。
下面 我们先来分别实现下从左往右变化的TextView和颜色从右往左变化的TextView。
首先,自定义一个View继承自TextView,为什么不继承自View?因为TextView 已经帮我们做了很多了,比如测量控件的大小以及一些兼容性问题上,我们在TetxView上做扩展会更省心省力。
下面,我们来自定义一下这个控件:
首先:我们需要两个颜色,一个是变化前的颜色,一个是变化后的颜色。暂且叫他们previousColor(变化前),changeColor(变化后),下面我们就来自定义下这个属性:
<declare-styleable name="ColorChangeTextView">
<!-- 修改之前的颜色 -->
<attr name="previousColor" format="color"/>
<!-- 修改之后的颜色 -->
<attr name="changeColor" format="color"/>
</declare-styleable>
第二步,在布局中使用这个属性
<com.justh.dell.colorchangetextviewdemo.ColorChangeTextView
android:id="@+id/colorchangetextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello JUSTH"
android:layout_marginTop="30dp"
android:layout_marginLeft="20dp"
android:textSize="30dp"
app:previousColor="@color/colorPrimaryDark"
app:changeColor="@color/colorAccent"/>
在这里,我想大家应该能够感受到继承自TextView的好处了吧 ,textSize啥的属性随便用啊,老铁!
第三步,下面,我们就该在自定义DE View中获取这些属性值,并设置属性值到对应的使用位置
public class ColorChangeTextView extends TextView {
private int mPreviousColor = Color.BLUE;
private int mChangeColor = Color.RED;
private Paint mPreviousPaint;
private Paint mChangePaint;
private Rect bounds = new Rect();
private float currentOffset = 0.0f;
//当前颜色变化的方向
private Direction mDirection = Direction.LEFT_TO_RIGHT;
//表示颜色变化的方向
public enum Direction{
LEFT_TO_RIGHT,RIGHT_TO_LEFT;
}
public ColorChangeTextView(Context context) {
this(context,null);
}
public ColorChangeTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ColorChangeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ColorChangeTextView);
mPreviousColor = typedArray.getColor(R.styleable.ColorChangeTextView_previousColor,getTextColors().getDefaultColor());
mChangeColor = typedArray.getColor(R.styleable.ColorChangeTextView_changeColor,getTextColors().getDefaultColor());
//回收
typedArray.recycle();
//设置画笔
mPreviousPaint = getColorPaint(mPreviousColor);
mChangePaint = getColorPaint(mChangeColor);
bounds = new Rect();
}
private Paint getColorPaint(int color){
Paint paint = new Paint();
paint.setColor(color);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setTextSize(60);
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
//自己来画,调用TextView的画的方法,就会把文字都画上同一种颜色
//super.onDraw(canvas);
if(mDirection == Direction.LEFT_TO_RIGHT){
drawText(canvas,mChangePaint,0,(int) (getWidth()*currentOffset));
drawText(canvas,mPreviousPaint,(int) (getWidth()*currentOffset),getWidth());
}else{
drawText(canvas,mChangePaint,(int) (getWidth()*(1-currentOffset)),getWidth());
drawText(canvas,mPreviousPaint,0,(int) (getWidth()*(1-currentOffset)));
}
}
private void drawText(Canvas canvas,Paint paint,int start,int end){
canvas.save();
String text = getText().toString();
//默认画在中心位置上
paint.getTextBounds(text,0,text.length(),bounds);
//计算基线
Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top)/2 - fontMetricsInt.bottom;
int baseLine = getHeight()/2 + dy;
Rect rect = new Rect(start,0, end,getHeight());
canvas.clipRect(rect);
canvas.drawText(text,getWidth()/2-bounds.width()/2,baseLine,paint);
//记得在裁剪操作之后,还原到之前的状态 这样 才能继续使用
canvas.restore();
}
//设置当前颜色变化的百分比
public void setCurrentOffset(float currentOffset) {
this.currentOffset = currentOffset;
invalidate();
}
//设置当前颜色变化的方向
public void setDirection(Direction direction) {
mDirection = direction;
}
//设置变化的颜色
public void setChangeColor(int changeColor) {
this.mChangePaint.setColor(changeColor);
}
//设置没变的颜色
public void setPreviourColor(int previourColor) {
this.mPreviousPaint.setColor(previourColor);
}
}
代码中,使用了一个canvas.clipRect()的函数,该函数是截取了画布的一块区域,来显示对应的该区域的操作!
下面 我们在Activity中 设置了两个方向的执行按钮,使用属性动画让效果动起来:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button left_right;
private Button right_left;
private ColorChangeTextView colorChangeTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
left_right = (Button) findViewById(R.id.left_right);
right_left = (Button) findViewById(R.id.right_left);
colorChangeTextView = (ColorChangeTextView) findViewById(R.id.colorchangetextview);
left_right.setOnClickListener(this);
right_left.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.left_right:
//从左到右
leftToRight();
break;
case R.id.right_left:
//从右到左
rightToLeft();
break;
}
}
public void leftToRight(){
colorChangeTextView.setDirection(ColorChangeTextView.Direction.LEFT_TO_RIGHT);
ValueAnimator animator = ObjectAnimator.ofFloat(0,1);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (float) animation.getAnimatedValue();
colorChangeTextView.setCurrentOffset(offset);
}
});
animator.start();
}
public void rightToLeft(){
colorChangeTextView.setDirection(ColorChangeTextView.Direction.RIGHT_TO_LEFT);
ValueAnimator animator = ObjectAnimator.ofFloat(0,1);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (float) animation.getAnimatedValue();
colorChangeTextView.setCurrentOffset(offset);
}
});
animator.start();
}
}
下面,就是效果了,请看大屏幕,哈哈哈!