初始化我就不说了,先思考我们需要什么属性,这里我就随便写了两个,一个是变色的颜色,一个是正常的颜色,当然也可以是默认的字体颜色,我们在attr
里面申明
<declare-styleable name="ColorTrackTextView">
<attr name="originColor" format="color" />
<attr name="changeColor" format="color" />
</declare-styleable>
private int mOriginColor;//不变化的颜色
private int mChangeColor;//变化的颜色
private Paint mOriginPaint, mChangePaint;
private void init(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);
mOriginColor = ta.getColor(R.styleable.ColorTrackTextView_originColor, Color.BLACK);
mChangeColor = ta.getColor(R.styleable.ColorTrackTextView_changeColor, Color.RED);
ta.recycle();
mOriginPaint = new Paint();
mOriginPaint.setColor(mOriginColor);
mOriginPaint.setAntiAlias(true);
mOriginPaint.setTextSize(getTextSize());
mChangePaint = new Paint();
mChangePaint.setColor(mChangeColor);
mChangePaint.setAntiAlias(true);
mChangePaint.setTextSize(getTextSize());
}
因为我们选择了继承的是TextView
,所以我们就不进行 onMeasure()
,我们重写onDraw()
,覆盖原有的绘制逻辑,我们自己来绘制,这里我们主要使用canvas.clipRect(rect)
这个函数来实现裁剪,我们先来测试:
//思路:利用clipRect 来裁剪 使用两个画笔
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas); //不使用TextView的绘制 自己画
canvas.save();
int mid = 500;
Rect rect = new Rect(0, 0, mid, getHeight());
canvas.clipRect(rect);
String text = getText().toString();
int x = (int) (getPaddingLeft() + getWidth() / 2 - mOriginPaint.measureText(text) / 2);
int y = getPaddingTop() + DisplayUtil.getTextBaseLine(getHeight(), mOriginPaint);
canvas.drawText(text, x, y, mChangePaint);
canvas.restore();
canvas.save();
rect.set(mid, 0, getWidth(), getHeight());
canvas.clipRect(rect);
canvas.drawText(text, x, y, mOriginPaint);
canvas.restore();
}
<com.zzw.customview.view.ColorTrackTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/colortv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:text="1111111"
android:textSize="50sp"
app:changeColor="@color/colorAccent"
app:originColor="@color/colorPrimary" />
可以看到,我们是有效果的,因为我们考略到要和 ViewPager
一起配合使用,所以我们定义一个float
类型的mCurrentProgress
属性,用于表示当前的滑动进度,在设置一个方向,颜色是从左到右变化还是从右到左的变化
//不同的朝向
public static final int DIRECTION_LEFT_TO_RIGHT = 1;//从左边变色
public static final int DIRECTION_RIGHT_TO_LEFT = 2;//从右边变色
private int mDirection = DIRECTION_LEFT_TO_RIGHT;
//当前进度
private float mCurrentProgress;
接下来我们修改onDraw()
以及优化一下赘余代码:
//思路:利用clipRect 来裁剪 使用两个画笔
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas); //不使用TextView的绘制 自己画
int mid = comMiddle();
if (mDirection == DIRECTION_LEFT_TO_RIGHT) {
drawText(canvas, mChangePaint, 0, mid); //画左边 颜色
drawText(canvas, mOriginPaint, mid, getWidth());//画右边
} else {
mid = getWidth() - mid;
drawText(canvas, mChangePaint, mid, getWidth());//画右边 颜色
drawText(canvas, mOriginPaint, 0, mid); //画左边
}
}
/**
* 根据当前进度算出中间值
*
* @return
*/
private int comMiddle() {
return (int) (mCurrentProgress * getWidth());
}
/**
* 根据start end 确定rect绘制文字
*
* @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);
String text = getText().toString();
int x = (int) (getPaddingLeft() + getWidth() / 2 - paint.measureText(text) / 2);
int y = getPaddingTop() + DisplayUtil.getTextBaseLine(getHeight(), paint);
canvas.drawText(text, x, y, paint);
canvas.restore();
}
接下来我们进行测试
public void leftToRight(View view) {
mColorTrackTextView.setDirection(ColorTrackTextView.DIRECTION_LEFT_TO_RIGHT);
startAnim(0, 1);
}
public void RightToLeft(View view) {
mColorTrackTextView.setDirection(ColorTrackTextView.DIRECTION_RIGHT_TO_LEFT);
startAnim(0, 1);
}
private void startAnim(float startPro, float endPro) {
ValueAnimator animator = ObjectAnimator.ofFloat(startPro, endPro);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentProgress = (float) animation.getAnimatedValue();
mColorTrackTextView.setCurrentProgress(currentProgress);
}
});
animator.start();
}
就会得到如下图的效果:
感觉离成功近了一步,这里我们顺便优化了一个性能的问题,因为是不端的调用setCurrentProgress()
方法进行重新绘制,所以这里我们加个判断:
public void setCurrentProgress(float currentProgress) {
if (mCurrentProgress == currentProgress)//当前进度相同就不执行下一步
return;
this.mCurrentProgress = currentProgress;
invalidate();
}
让它重复的时候不进行重绘,这只是一个小细节,接下来我们和ViewPager
配合使用。我们在开发中一般遇到的是根据一个数据源,然后动态的添加Fragment
和ViewPager
进行关联,这里我们模拟这个场景。我们使用一个LinearLayout
来管理这些字体变色的view
, ViewPager
的OnPageChangeListener
来管理字体变色,布局为下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:id="@+id/indicator_view"
android:layout_height="wrap_content"/>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/view_pager"
android:layout_weight="1"
/>
</LinearLayout>
然后我们在代码中动态的添加:
package com.zzw.customview;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.zzw.customview.view.ColorTrackTextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by zzw on 2017/6/15.
* Version:
* Des: 字体变色和viewpager配合使用
*/
public class ViewPagerActivity extends AppCompatActivity {
private String[] items = {"热点", "推荐", "社会", "图片", "科技", "运动"};
private LinearLayout mIndicatorContainer;// 变成通用的
private List<ColorTrackTextView> mIndicators;
private ViewPager mViewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
mIndicators = new ArrayList<>();
mIndicatorContainer = (LinearLayout) findViewById(R.id.indicator_view);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
initIndicator();
initViewPager();
}
/**
* 初始化ViewPager
*/
private void initViewPager() {
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return ItemFragment.newInstance(items[position]);
}
@Override
public int getCount() {
return items.length;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
});
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.e("TAG", "position -> " + position + " positionOffset -> " + positionOffset + " positionOffsetPixels->" + positionOffsetPixels);
// position 代表当前的位置
// positionOffset 代表滚动的 0 - 1 百分比 左滑 1->0 右滑-> 0-1
// 1.左边 位置 position
ColorTrackTextView left = mIndicators.get(position);
left.setDirection(ColorTrackTextView.DIRECTION_RIGHT_TO_LEFT);
left.setCurrentProgress(1 - positionOffset);
try {
ColorTrackTextView right = mIndicators.get(position + 1);
right.setDirection(ColorTrackTextView.DIRECTION_LEFT_TO_RIGHT);
right.setCurrentProgress(positionOffset);
} catch (Exception e) {
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* 初始化可变色的指示器
*/
private void initIndicator() {
for (int i = 0; i < items.length; i++) {
// 动态添加颜色跟踪的TextView
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.weight = 1;
ColorTrackTextView colorTrackTextView = new ColorTrackTextView(this);
// 设置颜色
colorTrackTextView.setTextSize(20);
colorTrackTextView.setChangeColor(Color.RED);
colorTrackTextView.setText(items[i]);
colorTrackTextView.setLayoutParams(params);
// 把新的加入LinearLayout容器
mIndicatorContainer.addView(colorTrackTextView);
// 加入集合
mIndicators.add(colorTrackTextView);
}
}
这里我们发现左右滑动的时候可以实现了,但是点击tab
的时候还会出现上一个没有变色的情况,这里我就不上图了,我们直接写一个函数,在选中之后把重新设置颜色即可。
private void selectPos(int pos) {
for (int i = 0; i < mIndicators.size(); i++) {
ColorTrackTextView colorTrackTextView = mIndicators.get(i);
if (i == pos) {
colorTrackTextView.setCurrentProgress(1.0f);
} else {
colorTrackTextView.setCurrentProgress(0.0f);
}
}
}
最后要说的是,优化问题,在这篇文章中我们在绘制的过程中就已经进行优化了,我们要养成这种好习惯,不管是代码上还是性能上。
下载地址:https://github.com/ChinaZeng/CustomView