今天給大家分享的是今日頭條頂部文字變色效果的實作,首先我們來看一下,實際中和我們最終要做出來的效果是什麼樣的。
效果呢就是像上面這樣的,那我們怎麼樣來實作呢?
既然是文字,為了省卻麻煩,我們就直接寫我們自己的自定義View去繼承自系統的TextView,這樣也會省去很多的代碼。
我們先為其定義兩個屬性,普通顔色和變色的顔色。
定義我們的屬性檔案
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ChangeTextColor">
<!--普通顔色-->
<attr name="normalColor" format="color"/>
<!--變化的顔色-->
<attr name="changeColor" format="color"/>
</declare-styleable>
</resources>
主要代碼:
// 普通字型的畫筆
private Paint mNormalPaint;
// 變色字型的畫筆
private Paint mChangePaint;
// 目前的進度
private float mCurrentProgress = 0.0f;
private Direction mDirection = FROME_LEFT_TO_RIGHT;
//方向
public enum Direction {
FROME_LEFT_TO_RIGHT, FROME_RIGHT_TO_LEFT
}
public ChangeTextColor(Context context) {
this(context, null);
}
public ChangeTextColor(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ChangeTextColor(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//擷取屬性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChangeTextColor);
int mNormalColor = array.getColor(R.styleable.ChangeTextColor_normalColor, getTextColors().getDefaultColor());
int mChangeColor = array.getColor(R.styleable.ChangeTextColor_changeColor, getTextColors().getDefaultColor());
array.recycle();
//設定普通顔色畫筆
mNormalPaint = new Paint();
mNormalPaint.setAntiAlias(true);//抗鋸齒
mNormalPaint.setColor(mNormalColor);
mNormalPaint.setDither(true);// 防抖動
mNormalPaint.setTextSize(getTextSize());
//設定變化顔色畫筆
mChangePaint = new Paint();
mChangePaint.setAntiAlias(true);//抗鋸齒
mChangePaint.setColor(mChangeColor);
mChangePaint.setDither(true);// 防抖動
mChangePaint.setTextSize(getTextSize());
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);不要用系統的 我們自己畫
//定一個中間值去畫
int midleValue = (int) (mCurrentProgress * getWidth());
if (mDirection == FROME_LEFT_TO_RIGHT) {
drawText(canvas, mChangePaint, 0, midleValue);
drawText(canvas, mNormalPaint, midleValue, getWidth());
} else {
drawText(canvas, mChangePaint, getWidth() - midleValue, getWidth());
drawText(canvas, mNormalPaint, 0, getWidth() - midleValue);
}
}
/**
* 繪制text
*
* @param canvas
* @param paint
* @param start
* @param end
*/
private void drawText(Canvas canvas, Paint paint, int start, int end) {
canvas.save();
Rect react = new Rect(start, 0, end, getHeight());
canvas.clipRect(react);
String text = getText().toString();
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
//從什麼地方開始畫文字
int x = getWidth() / 2 - bounds.width() / 2;
//獲得基線位置
Paint.FontMetricsInt fontMetricsInt = paint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = getHeight() / 2 + dy;
canvas.drawText(text, x, baseLine, paint);
canvas.restore();
}
/**
* 設定方向
*
* @param direction
*/
public void setDirection(Direction direction) {
this.mDirection = direction;
}
/**
* 設定進度
*
* @param currentProgress
*/
public void setCurrentProgress(float currentProgress) {
this.mCurrentProgress = currentProgress;
invalidate();
}
public void setChangeColor(int changeColor) {
this.mChangePaint.setColor(changeColor);
}
public void setNormaleColor(int normalColor) {
this.mNormalPaint.setColor(normalColor);
}
Rect react = new Rect(start, 0, end, getHeight());
canvas.clipRect(react);
在這裡我給大家說一下這個屬性,就是我們畫出的文字,是通過這個來裁剪的,這也是我們實作該效果的很重要的一步,在這裡還比較繞
我們在正常情況下在螢幕上畫出文字是完整的,那麼使用canvas.clipRect()方法是怎樣的呢,首先我們需要一個裁剪區域React
下面給大家展示一下我們位置設定的不同會導緻什麼樣的結果,通過圖來說也許會更明白
Rect react = new Rect(left, top, right, bottom);
Rect react = new Rect(0, 0, 10, getHeight());//right為10
Rect react = new Rect(0, 0, 50, getHeight());//right為50
Rect react = new Rect(0, 0, 90, getHeight());//right為90
Rect react = new Rect(0, 0, 130, getHeight());//right為130
看到這裡我們的思路就是這樣的,用兩隻畫筆去話我們的文字,分别去裁剪我們的文字,左邊裁一定的比例,右邊裁一定的比例,這樣正好就拼出整個完整的文字,然後我們隻要不斷地去改變我們裁剪區域的比例,那麼就可以實作我們的文字變色,在代碼中已經寫得比較詳細了,這裡就不贅述了。
使用:
public class HomePageActivity extends AppCompatActivity {
private String[] items = {"關注","推薦", "曆史", "美食", "熱點", "視訊", "社會"};
private List<ChangeTextColor> mIndicators;
private ViewPager mViewPager;
private LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_page);
linearLayout = (LinearLayout) findViewById(R.id.ll_top);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mIndicators = new ArrayList<>();
initIndicator();
initViewPager();
}
private void initViewPager() {
//設定adapter
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return FragmentContent.newInstance(items[position]);
}
@Override
public int getCount() {
return items.length;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
});
mViewPager.setCurrentItem(1);
//設定viewpager的監聽
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
ChangeTextColor leftDirection = mIndicators.get(position);
leftDirection.setDirection(ChangeTextColor.Direction.FROME_RIGHT_TO_LEFT);
leftDirection.setCurrentProgress(1-positionOffset);
try {
ChangeTextColor rightDirection = mIndicators.get(position+1);
rightDirection.setDirection(ChangeTextColor.Direction.FROME_LEFT_TO_RIGHT);
rightDirection.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++) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.weight = 1;
ChangeTextColor changeTextColor = new ChangeTextColor(this);
// 設定顔色
changeTextColor.setTextSize(25);
changeTextColor.setChangeColor(Color.RED);
changeTextColor.setText(items[i]);
changeTextColor.setLayoutParams(params);
// 把新的加入LinearLayout容器
linearLayout.addView(changeTextColor);
// 加入集合
mIndicators.add(changeTextColor);
}
}
}
布局檔案就很簡單了,viewpager+linearlayout
Fragment就是一些内容顯示了,代碼可以自己down,歡迎朋友們提出意見。
github位址:點選打開連結