簡介
本篇是來自鴻洋_大神的Android 自定義控件玩轉字體變色 打造炫酷ViewPager指示器這篇博客,剛開始看時覺得不是很好理解,現在自己減去了他的一些代碼,自己寫的一個,也實現了同樣的效果,感覺好理解多了。
先看一下實現後的效果:
要實現這樣的文字跟隨viewpager的滑動而逐漸改變顏色的效果,這裏很明顯底色字一直在的,所以我們要考慮的主要是紅色字體的繪製。繪製紅色字體用的是canvas的clipRect()方法。根據要改變的寬度係數,切割要繪製的位置。這裏運用了自定義屬性,方便我們修改一些控件的屬性。
1,自定義屬性
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>
源碼:點我下載