本篇是来自鸿洋_大神的Android 自定义控件玩转字体变色 打造炫酷ViewPager指示器这篇博客,刚开始看时觉得不是很好理解,现在自己减去了他的一些代码,自己写的一个,也实现了同样的效果,感觉好理解多了。
先看一下实现后的效果:
要实现这样的文字跟随viewpager的滑动而逐渐改变颜色的效果,这里很明显底色字一直在的,所以我们要考虑的主要是红色字体的绘制。绘制红色字体用的是canvas的clipRect()方法。根据要改变的宽度系数,切割要绘制的位置。这里运用了自定义属性,方便我们修改一些控件的属性。
attrs.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="text" format="string"/>
<attr name="textSize" format="dimension"/>
<attr name="textOriginColor" format="color"/>
<attr name="textChangeColor" format="color"/>
<attr name="progress" format="float"/>
<attr name="direction" >
<enum name="left" value="0" />
<enum name="right" value="1" />
</attr>
<declare-styleable name = "colortractview">
<attr name="text" />
<attr name="textSize" />
<attr name="textOriginColor" />
<attr name="textChangeColor" />
<attr name="progress" />
<attr name="direction" />
</declare-styleable>
</resources>
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:raise="http://schemas.android.com/apk/res/com.raise.colortrackview" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fff" >
<com.raise.colortrackview.ColorTrackView android:id="@+id/colortractview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="#ddd" raise:text="ColorTract测试" raise:textChangeColor="#ff0000" raise:textSize="30sp" />
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" >
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="left" />
<Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="rihgt" />
</LinearLayout>
</FrameLayout>
ColorTrackView.java源码
package com.raise.colortrackview;
import com.raise.colortrackview.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class ColorTrackView extends View {
//一些默认值
private static final int DEFAULT_TEXTSIZE = 20;
private static final int DIRECTION_LEFT = 0;
private static final int DIRECTION_RIGHT = 1;
private static final int DEFAULT_ORIGHT_COLOR = Color.BLACK;
private static final int DEFAULT_CHANGE_COLOR = Color.RED;
/** * 设置颜色变化方向值 * @author raise * */
public enum Direction{
Left,Right
}
/** * 字体画笔 */
private Paint mPaint;
/** * 要画出的文字 */
private String mText;
/** * 文字大小 */
private int mTextSize;
/** * 原文字颜色 */
private int mOriginColor;
/** * 拖动后的文字颜色 */
private int mChangeColor;
/** * 变化进度 */
private float mProgress;
/** * 变化方向 */
private int mDirection;
/** * view的宽 */
private int mWidth;
/** * view的高 */
private int mHeight;
public ColorTrackView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
//读取自定义属性
initDatas(context, attrs);
//设置默认标题
mText = mText == null ? "标题" : mText;
mPaint.setTextSize(mTextSize);
//字体的宽度和高度,作为该控件的宽度和高度
mWidth = (int) mPaint.measureText(mText);
mHeight = (int) (mPaint.descent() - mPaint.ascent());
// setBackgroundColor(Color.parseColor("#f1f1f1"));
}
private void initDatas(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.colortractview);
mText = ta.getString(R.styleable.colortractview_text);
mTextSize = ta.getDimensionPixelOffset(
R.styleable.colortractview_textSize, sp2px(DEFAULT_TEXTSIZE));
mDirection = ta.getInt(R.styleable.colortractview_direction,
DIRECTION_LEFT);
mOriginColor = ta.getColor(R.styleable.colortractview_textOriginColor,
DEFAULT_ORIGHT_COLOR);
mChangeColor = ta.getColor(R.styleable.colortractview_textChangeColor,
DEFAULT_CHANGE_COLOR);
mProgress = ta.getFloat(R.styleable.colortractview_progress, 0f);
ta.recycle();
}
public ColorTrackView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ColorTrackView(Context context) {
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// view的width,height等于字体的
widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth,
MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mHeight,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
int startX = (int) (mProgress * mWidth);
// 第一次绘出原字体
mPaint.setColor(mOriginColor);
canvas.drawText(mText, 0, mHeight - mPaint.descent(), mPaint);
mPaint.setColor(mChangeColor);
canvas.save();
//第二次绘出变色字体
if (mDirection == DIRECTION_LEFT) {
//变色字出现在左边,起点当然是(0,0)
canvas.clipRect(0, 0, startX, mHeight);
} else if (mDirection == DIRECTION_RIGHT) {
//变色字出现在右边,终点当然是(mWidth,mHeight)
canvas.clipRect(mWidth-startX, 0, mWidth, mHeight);
}
//在指定区域绘出变色字
canvas.drawText(mText, 0, mHeight - mPaint.descent(), mPaint);
canvas.restore();
}
private int dp2px(int value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
value, getResources().getDisplayMetrics());
}
private int sp2px(int value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
value, getResources().getDisplayMetrics());
}
public int getmDirection() {
return mDirection;
}
public void setDirection(int direction) {
this.mDirection = direction;
}
public void setProgress(float progress) {
this.mProgress = progress;
//注意这里要重绘
invalidate();
}
}
和大神区别在于,我使用了字体的大小,做为该View的大小,这样理解起来简单了许多,在使用的时候,只要在外部多加一层Linearlayout就可以了。
MainActivity.java源码:
public class MainActivity extends Activity implements OnClickListener {
ColorTrackView view ;
Button leftbButton;
Button rightButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (ColorTrackView) findViewById(R.id.colortractview);
leftbButton = (Button) findViewById(R.id.button1);
rightButton = (Button) findViewById(R.id.button2);
leftbButton.setOnClickListener(this);
rightButton.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v) {
if (v == leftbButton) {
view.setDirection(0);
Toast.makeText(MainActivity.this, "left", 1).show();
ObjectAnimator.ofFloat(view, "progress", 0f,1f).setDuration(2000).start();
}else if (v == rightButton) {
Toast.makeText(MainActivity.this, "right", 1).show();
view.setDirection(1);
ObjectAnimator.ofFloat(view, "progress", 0f,1f).setDuration(2000).start();
}
}
}
效果图:
和预想的一样,看来简化后没问题。
下面看下将其使用到viewpager上。
TabFragment.java
public class TabFragment extends Fragment {
private static final String TITLE = "title";
private String mTitle = "default title";
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle!=null) {
mTitle = bundle.getString(TITLE);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView view = new TextView(getActivity());
view.setTextSize(30);
Random r = new Random();
view.setBackgroundColor(Color.argb(r.nextInt(120), r.nextInt(255),
r.nextInt(255), r.nextInt(255)));
view.setGravity(Gravity.CENTER);
view.setText(mTitle);
return view;
}
public static Fragment newInstance(String title) {
TabFragment fragment = new TabFragment();
Bundle bundle = new Bundle();
bundle.putString(TITLE, title);
fragment.setArguments(bundle);
return fragment;
}
}
TestActivity.java
public class TestActivity extends FragmentActivity implements OnPageChangeListener {
private String[] mTitles = { "生活", "科技", "体育" };
private ViewPager viewPager;
//装载指示器的list
private List<ColorTrackView> viewList = new ArrayList<ColorTrackView>();
private ColorTrackView colorView1;
private ColorTrackView colorView2;
private ColorTrackView colorView3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
initView();
viewPager.setAdapter(adapter);
viewPager.setOnPageChangeListener(this);
viewList.add(colorView1);
viewList.add(colorView2);
viewList.add(colorView3);
viewList.get(0).setProgress(1);
}
private void initView() {
viewPager = (ViewPager) findViewById(R.id.viewpage);
colorView1 = (ColorTrackView) findViewById(R.id.view_color1);
colorView2 = (ColorTrackView) findViewById(R.id.view_color2);
colorView3 = (ColorTrackView) findViewById(R.id.view_color3);
}
FragmentPagerAdapter adapter = new FragmentPagerAdapter(
getSupportFragmentManager()) {
@Override
public int getCount() {
return mTitles.length;
}
@Override
public Fragment getItem(int arg0) {
return TabFragment.newInstance(mTitles[arg0]);
}
};
@Override
public void onPageScrollStateChanged(int arg0) {
}
/* * arg0是左边的fragment坐标,arg1,0-1滑动系数,arg2隐藏的宽度 */
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// 不可滑动时退出
if (arg1 == 0f) {
return;
}
// 得到左边的view
ColorTrackView leftView = viewList.get(arg0);
// 得到右边的view
ColorTrackView rightView = viewList.get(arg0 + 1);
// 设置左边view指示器状态
leftView.setDirection(1);
leftView.setProgress(1 - arg1);
// 设置右边view指示器状态
rightView.setDirection(0);
rightView.setProgress(arg1);
}
@Override
public void onPageSelected(int arg0) {
}
}
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:raise="http://schemas.android.com/apk/res/com.raise.colortrackview" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:background="#f1f1f1" android:gravity="center_vertical" android:orientation="horizontal" android:weightSum="3" >
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="horizontal" >
<com.raise.colortrackview.ColorTrackView android:id="@+id/view_color1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" raise:text="生活" raise:textChangeColor="#c96666" />
</LinearLayout>
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="horizontal" >
<com.raise.colortrackview.ColorTrackView android:id="@+id/view_color2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" raise:text="科技" raise:textChangeColor="#c96666" />
</LinearLayout>
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:orientation="horizontal" >
<com.raise.colortrackview.ColorTrackView android:id="@+id/view_color3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" raise:text="体育" raise:textChangeColor="#c96666" />
</LinearLayout>
</LinearLayout>
<android.support.v4.view.ViewPager android:id="@+id/viewpage" android:layout_width="match_parent" android:layout_height="match_parent" />
</LinearLayout>
源码:点我下载