实例图

Android 自定义变化的文本控件ColorChangeView_android

说明图

Android 自定义变化的文本控件ColorChangeView_App_02

/**
* 有颜色过渡变化的textview
*
* @Project App_View
* @Package com.android.view.colortextview
* @author chenlin
* @version 1.0
* @Note TODO
*/
/**
* 有颜色过渡变化的textview
*
* @Project App_View
* @Package com.android.view.colortextview
* @author chenlin
* @version 1.0
* @Note TODO
*/
public class ColorChangeView extends View {
public static final int DIRECTION_LEFT = 0;
public static final int DIRECTION_RIGHT = 1;
public static final int DIRECTION_TOP = 2;
public static final int DIRECTION_BOTTOM = 3;
public static final String DEFAULT_TEXT = "颜色变化";

// 默认字体大小
private static final int DEF_TEXT_SIZE = 0;
// 文本内容
private String mText;
// 文本大小
private int mTextSize = sp2px(30);
// 文本原来颜色
private int mOriginColor = 0xff000000;
// 文本改变后的颜色
private int mChangeColor = 0xffff0000;
// 改变颜色时的进度百分比
private float mProgress;
// 改变颜色的方向,默认从左边开始变色
private int mDirection = DIRECTION_LEFT;
// 绘制文本的画笔
private Paint mPaint;

// ---测量信息----------------------------------------
// 文本宽度
private int mTextWidth;
// 文本高度
private int mTextHeight;
// 文本区域
private Rect mTextBound = new Rect();

// 开始移动坐标
private int mTextStartX;
private int mTextStartY;

/** 总共分四个方向 */
public enum Direction {
LEFT, RIGHT, TOP, BOTTOM;
}

public ColorChangeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}

public ColorChangeView(Context context) {
this(context, null);
}

private void init(Context context, AttributeSet attrs) {
// 初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);

// 初始化自定义属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColorChangeView);
mText = ta.getString(R.styleable.ColorChangeView_text);
mTextSize = ta.getDimensionPixelSize(R.styleable.ColorChangeView_text_size, mTextSize);
mOriginColor = ta.getColor(R.styleable.ColorChangeView_text_origin_color, mOriginColor);
mChangeColor = ta.getColor(R.styleable.ColorChangeView_text_change_color, mChangeColor);
mProgress = ta.getFloat(R.styleable.ColorChangeView_progress, 0);
mDirection = ta.getInt(R.styleable.ColorChangeView_direction, mDirection);
ta.recycle();

// 为画笔设置文本大小
mPaint.setTextSize(mTextSize);
}

/**
* 测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 第一步:先测量文本的区域大小
measureText();
// 第二步:对视图测量
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
// 这个方法决定了当前View的大小
setMeasuredDimension(width, height);

// 从有文字的位置开始绘制
mTextStartX = (getMeasuredWidth() - mTextWidth) / 2;
mTextStartY = (getMeasuredHeight() - mTextHeight) / 2;

}

/**
* 测量高度
*
* @param heightMeasureSpec
* @return
*/
private int measureHeight(int heightMeasureSpec) {
int height = 0;

int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);

switch (heightMode) {
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
height = mTextBound.height();
height += getPaddingBottom() + getPaddingTop();
break;

}
return height = heightMode == MeasureSpec.AT_MOST ? Math.min(height, heightSize) : height;
}

/**
* 测量宽度
*
* @param widthMeasureSpec
* @return
*/
private int measureWidth(int widthMeasureSpec) {
int width = 0;

int widthtSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);

switch (widthMode) {
case MeasureSpec.EXACTLY:
width = widthtSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
width = mTextWidth;
width += getPaddingLeft() + getPaddingRight();
break;
}
return width = widthMode == MeasureSpec.AT_MOST ? Math.min(width, widthtSize) : width;
}

/**
* 对文本控件测量,得到绘制时的宽高
*/
private void measureText() {
mTextWidth = (int) mPaint.measureText(mText);

FontMetrics fm = mPaint.getFontMetrics();
// 文本的最低处-文本的最高处
mTextHeight = (int) Math.ceil(fm.descent - fm.top);

mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
// 获得高度
mTextHeight = mTextBound.height();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 水平移动距离
int distance_x = (int) (mProgress * mTextWidth + mTextStartX);
// 垂直移动距离
int distance_y = (int) (mProgress * mTextHeight + mTextStartY);

// 从左移动
if (mDirection == DIRECTION_LEFT) {
drawOriginLeft(canvas, distance_x);
drawChangeLeft(canvas, distance_x);
// 从右移动
} else if (mDirection == DIRECTION_RIGHT) {
drawOriginRight(canvas, distance_x);
drawChangeRight(canvas, distance_x);
// 从上移动
} else if (mDirection == DIRECTION_TOP) {
drawOriginTop(canvas, distance_y);
drawChangeTop(canvas, distance_y);
} else if (mDirection == DIRECTION_BOTTOM) {
// 从底部移动
drawOriginBottom(canvas, distance_y);
drawChangeBottom(canvas, distance_y);
}

}

/**
* 反转颜色
*/
public void reverseColor() {
int tmp = mOriginColor;
mOriginColor = mChangeColor;
mChangeColor = tmp;
}

/**
* 从左绘制变化的文本
*
* @param canvas
* @param hProgress
*/
private void drawChangeLeft(Canvas canvas, int distance_x) {
drawText_x(canvas, mChangeColor, mTextStartX, distance_x);
}

/**
* 从左绘制原来的文本
*
* @param canvas
* @param hProgress
*/
private void drawOriginLeft(Canvas canvas, int distance_x) {
drawText_x(canvas, mOriginColor, distance_x, mTextStartX + mTextWidth);
}

/**
* 从右边绘制原文本
*
* @param canvas
* @param distance_x
*/
private void drawOriginRight(Canvas canvas, int distance_x) {
drawText_x(canvas, mOriginColor, (int) (mTextStartX + (1 - mProgress) * mTextWidth), mTextStartX + mTextWidth);
}

/**
* 从右边绘制变化文本
*
* @param canvas
* @param distance_x
*/
private void drawChangeRight(Canvas canvas, int distance_x) {
drawText_x(canvas, mChangeColor, mTextStartX, (int) (mTextStartX + (1 - mProgress) * mTextWidth));
}

private void drawOriginTop(Canvas canvas, int distance_y) {
drawText_y(canvas, mOriginColor, mTextStartY, (int) (mTextStartY + mProgress * mTextHeight));
}

private void drawChangeTop(Canvas canvas, int distance_y) {
drawText_y(canvas, mChangeColor, (int) (mTextStartY + mProgress * mTextHeight), mTextStartY + mTextHeight);
}

private void drawChangeBottom(Canvas canvas, int distance_y) {
drawText_y(canvas, mChangeColor, (int) (mTextStartY + (1 - mProgress) * mTextHeight), mTextStartY + mTextHeight);
}

private void drawOriginBottom(Canvas canvas, int distance_y) {
drawText_y(canvas, mOriginColor, mTextStartY, (int) (mTextStartY + (1 - mProgress) * mTextHeight));
}

private boolean debug = false;
/**
* 水平绘制
*
* @param canvas
* @param color
* @param startX
* @param endX
*/
private void drawText_x(Canvas canvas, int color, int startX, int endX) {
mPaint.setColor(color);
if (debug) {
mPaint.setStyle(Style.STROKE);
// 第一步:先绘制矩形区域,在这之前,设定画笔的颜色
canvas.drawRect(startX, 0, endX, getMeasuredHeight(), mPaint);
}
canvas.save(Canvas.CLIP_SAVE_FLAG);
// 第二步:实现动画绘制,在之前,先保存绘制好的区域
canvas.clipRect(startX, 0, endX, getMeasuredHeight());
// 第三步:绘制出整个文本, mPaint.descent() + mPaint.ascent() = 字体的高 getMeasuredHeight是view的高
canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2), mPaint);
// 第四步:恢复画布
canvas.restore();
}

/**
* 垂直绘制
*
* @param canvas
* @param color
* @param startY
* @param endY
*/
private void drawText_y(Canvas canvas, int color, int startY, int endY) {
mPaint.setColor(color);
if (debug) {
mPaint.setStyle(Style.STROKE);
// 第一步:先绘制矩形区域,在这之前,设定画笔的颜色
canvas.drawRect(0, startY, getMeasuredWidth(), endY, mPaint);
}
canvas.save(Canvas.CLIP_SAVE_FLAG);
// 第二步:实现动画绘制,在之前,先保存绘制好的区域
canvas.clipRect(0, startY, getMeasuredWidth(), endY);
// 第三步:绘制出整个文本, mPaint.descent() + mPaint.ascent() = 字体的高 getMeasuredHeight是view的高
canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2), mPaint);
// 第四步:恢复画布
canvas.restore();
}

// --Set Get --向外提供的方法--------------------------------------------------------

public void setDirection(int direction) {
this.mDirection = direction;
}

public float getProgress() {
return mProgress;
}

public void setProgress(float progress) {
this.mProgress = progress;
invalidate();
}

public int getTextSize() {
return mTextSize;
}

public void setTextSize(int textSize) {
this.mTextSize = textSize;
mPaint.setTextSize(mTextSize);
requestLayout();
invalidate();
}

public void setText(String text) {
this.mText = text;
requestLayout();
invalidate();
}

public int getTextOriginColor() {
return mOriginColor;
}

public void setTextOriginColor(int originColor) {
this.mOriginColor = originColor;
invalidate();
}

public int getTextChangeColor() {
return mChangeColor;
}

public void setTextChangeColor(int changeColor) {
this.mChangeColor = changeColor;
invalidate();
}

// ---像素转化函数----------------------------------------------------
public int dp2px(float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
}

public int sp2px(float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dpVal, getResources().getDisplayMetrics());
}

// ----保存和恢复数据-----------------------------------------------------------------

private static final String KEY_STATE_PROGRESS = "key_progress";
private static final String KEY_DEFAULT_STATE = "key_default_state";

@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putFloat(KEY_STATE_PROGRESS, mProgress);
bundle.putParcelable(KEY_DEFAULT_STATE, super.onSaveInstanceState());
return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {

if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mProgress = bundle.getFloat(KEY_STATE_PROGRESS);
super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT_STATE));
return;
}
super.onRestoreInstanceState(state);
}

}

运用

public class HomeActivity extends ListActivity {

private String[] mTitles = new String[] { "简单使用", "变化应用" };

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getListView().setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mTitles));
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = null;
switch (position) {
case 0:
intent = new Intent(this,SimpleActivity.class);
break;
case 1:
intent = new Intent(this,ViewPagerActivity.class);
break;
}
if (intent != null) {
startActivity(intent);
}
}
}

1)简单运用

public class SimpleActivity extends Activity implements OnClickListener {
@ViewInject(R.id.id_changeTextColorView)
private ColorChangeView mView;
@ViewInject(R.id.id_left)
private Button mBtnLeft;
@ViewInject(R.id.id_right)
private Button mBtnRight;
@ViewInject(R.id.id_top)
private Button mBtnTop;
@ViewInject(R.id.id_bottom)
private Button mBtnBottom;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simpepager);
ViewUtils.inject(this);
initEvents();
}

private void initEvents() {
mBtnLeft.setOnClickListener(this);
mBtnRight.setOnClickListener(this);
mBtnTop.setOnClickListener(this);
mBtnBottom.setOnClickListener(this);
}

@Override
public void onClick(View v) {
if (v == mBtnLeft) {
mView.setDirection(ColorChangeView.DIRECTION_LEFT);
ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start();
}else if (v == mBtnRight) {
mView.setDirection(ColorChangeView.DIRECTION_RIGHT);
ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start();
}else if (v == mBtnTop) {
mView.setDirection(ColorChangeView.DIRECTION_TOP);
ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start();
}else if (v == mBtnBottom) {
mView.setDirection(ColorChangeView.DIRECTION_BOTTOM);
ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start();
}
}
}

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:koo="http://schemas.android.com/apk/res/com.android.view"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.android.view.colortextview.ColorChangeView
android:id="@+id/id_changeTextColorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#44ff0000"
android:padding="10dp"
koo:progress="0"
koo:text="北京我来了"
koo:text_change_color="#ffff0000"
koo:text_origin_color="#ff000000"
koo:text_size="60sp" />

<LinearLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal" >

<Button
android:id="@+id/id_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startLeft" />

<Button
android:id="@+id/id_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/id_left"
android:text="startRight" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="45dp"
android:layout_above="@id/ll"
android:gravity="center"
android:orientation="horizontal" >

<Button
android:id="@+id/id_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startTop" />

<Button
android:id="@+id/id_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/id_left"
android:text="startBottom" />
</LinearLayout>

</RelativeLayout>

2)使用viewpager展示

public class ViewPagerActivity extends FragmentActivity {
private String[] mTitles = new String[] { "简介", "评价", "相关" };
//创建viewpager
private ViewPager mViewPager;
//定义数据数组
private TabFragment[] mDatas = new TabFragment[mTitles.length];
//定义标题控件
private List<ColorChangeView> mTabs = new ArrayList<ColorChangeView>();

private FragmentPagerAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager);
initViews();
initDatas();
initEvenvts();
}



private void initViews() {
mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
mTabs.add((ColorChangeView) findViewById(R.id.id_tab_01));
mTabs.add((ColorChangeView) findViewById(R.id.id_tab_02));
mTabs.add((ColorChangeView) findViewById(R.id.id_tab_03));
}



private void initDatas() {
for (int i = 0; i < mTitles.length; i++) {
mDatas[i] = TabFragment.newInstance(mTitles[i]);
}

mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()){

@Override
public Fragment getItem(int position) {
return mDatas[position];
}

@Override
public int getCount() {
return mTitles.length;
}

};
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(0);
}



private void initEvenvts() {
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset > 0) {
ColorChangeView left = mTabs.get(position);
left.setDirection(ColorChangeView.DIRECTION_LEFT);
left.setProgress(1-positionOffset);
ColorChangeView right = mTabs.get(position+1);
right.setDirection(ColorChangeView.DIRECTION_RIGHT);
right.setProgress(positionOffset);
}
}

@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}

Fragment代码

public class TabFragment extends Fragment {
public static final String TITLE = "title";
private String mTitle = "Defaut Value";


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mTitle = getArguments().getString(TITLE);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
tv.setTextSize(60);
Random r = new Random();
tv.setBackgroundColor(Color.argb(r.nextInt(120), r.nextInt(255), r.nextInt(255), r.nextInt(255)));
tv.setText(mTitle);
tv.setGravity(Gravity.CENTER);
return tv;
}

public static TabFragment newInstance(String title) {
TabFragment tabFragment = new TabFragment();
Bundle bundle = new Bundle();
bundle.putString(TITLE, title);
//保存标题信息
tabFragment.setArguments(bundle);
return tabFragment;
}
}

相关布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:koo="http://schemas.android.com/apk/res/com.android.view"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/state_menu_item_selected"
android:orientation="horizontal" >

<com.android.view.colortextview.ColorChangeView
android:id="@+id/id_tab_01"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
koo:progress="1"
koo:text="简介"
koo:text_change_color="#ffff0000"
koo:text_origin_color="#ff000000"
koo:text_size="18sp" />

<com.android.view.colortextview.ColorChangeView
android:id="@+id/id_tab_02"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
koo:text="评价"
koo:text_change_color="#ffff0000"
koo:text_origin_color="#ff000000"
koo:text_size="18sp" />

<com.android.view.colortextview.ColorChangeView
android:id="@+id/id_tab_03"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
koo:text="相关"
koo:text_change_color="#ffff0000"
koo:text_origin_color="#ff000000"
koo:text_size="18sp" />

</LinearLayout>

<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</android.support.v4.view.ViewPager>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@android:color/holo_green_light"/> <!-- pressed -->
<item android:drawable="@android:color/holo_green_dark"/> <!-- default -->
</selector>