Android仿今日头条文字渐变效果
概述

绘制水平垂直居中的文本
采用画布裁剪实现渐变效果
绘制水平垂直居中的文本
文本水平居中
调用Paint的setTextAlign(Paint.Align.CENTER)方法
控件宽度 / 2 - 文字宽度 / 2计算文本的x轴坐标
文本垂直居中
获取View的中心位置
中心位置下移半个字体的高度
上移descent,达到文字的最终位置即BaseLine的位置
代码实现如下:
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float baseLine = (getHeight() + fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent;
为了方便理解,baseLine的计算,可参考下图:

画布裁剪实现渐变效果
//渐变部分private void drawGradientText(Canvas canvas) {//保存当前画布canvas.save();//文字水平居中方案二:x = getWidth() / 2 - 文字宽度 / 2float textWidth = mTextPaint.measureText(mText, 0, mText.length());float x = (getWidth() - textWidth) / 2;//文字垂直居中:BaseLine的计算 = getHeight() / 2 + 文字高度 / 2 - descentPaint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float textHeight = fontMetrics.descent - fontMetrics.ascent;float y = (getHeight() + textHeight) / 2 - fontMetrics.descent;mTextPaint.setColor(Color.RED);//先裁剪渐变区域文字要显示的区域float right = x + textWidth * mPercent;canvas.clipRect(x, 0, right, getHeight());//裁剪完成后再绘制文字canvas.drawText(mText, x, y, mTextPaint);//恢复画布canvas.restore();}//不变部分private void drawNormalText(Canvas canvas) {canvas.save();float textWidth = mTextPaint.measureText(mText, 0, mText.length());float x = (getWidth() - textWidth) / 2;Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float textHeight = fontMetrics.descent - fontMetrics.ascent;float y = (getHeight() + textHeight) / 2 - fontMetrics.descent;mTextPaint.setColor(Color.BLACK);//对不变区域文字进行裁剪,防止过度绘制(这个很重要)float left = x + textWidth * mPercent;canvas.clipRect(left, 0, x + textWidth, getHeight());canvas.drawText(mText, x, y, mTextPaint);canvas.restore();}
仿今日头条文字渐变效果实现思路
渐变控件关键代码:
public class ColorChangeTextView extends AppCompatTextView {private int mTextSize = sp2px(30);private int mTextColor = Color.BLACK;private int mTextColorChange = Color.RED;private TextPaint mTextPaint;private int mDirection = LEFT;//文件渐变方向protected static final int LEFT = 0;protected static final int RIGHT = 1;@IntDef(value = {LEFT, RIGHT})@Retention(RetentionPolicy.SOURCE)public @interface Direction {}private float mProgress;//文字渐变的进度public float getProgress() {return mProgress;}public void setProgress(float mProgress) {this.mProgress = mProgress;invalidate();}public void setDirection(@Direction int direction) {this.mDirection = direction;}public ColorChangeTextView(Context context) {this(context, null);}public ColorChangeTextView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ColorChangeTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initAttr(context, attrs);init();}private void initAttr(final Context context, @Nullable final AttributeSet attrs) {TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.ColorChangeTextView);mTextSize = ta.getDimensionPixelSize(R.styleable.ColorChangeTextView_text_size, mTextSize);mTextColor = ta.getColor(R.styleable.ColorChangeTextView_text_color, mTextColor);mTextColorChange = ta.getColor(R.styleable.ColorChangeTextView_text_color_change, mTextColorChange);mProgress = ta.getFloat(R.styleable.ColorChangeTextView_progress, 0);ta.recycle();}private void init() {mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);mTextPaint.setColor(mTextColor);mTextPaint.setTextSize(mTextSize);}@Overrideprotected void onDraw(Canvas canvas) {switch (mDirection){case LEFT:drawLeft(canvas);break;case RIGHT:drawRight(canvas);break;}}private void drawLeft(Canvas canvas){//绘制底部不变部分canvas.save();String text = getText().toString();float textWidth = mTextPaint.measureText(text);Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float textHeight = fontMetrics.descent - fontMetrics.ascent;float x = (getWidth() - textWidth) / 2;float baseLine = (getHeight() + textHeight) / 2 - fontMetrics.descent;float left = x + textWidth * mProgress;canvas.clipRect(left,0,x + textWidth,getHeight());mTextPaint.setColor(mTextColor);canvas.drawText(text,x,baseLine,mTextPaint);canvas.restore();//绘制顶部渐变部分canvas.save();float right = x + textWidth * mProgress;canvas.clipRect(x,0,right,getHeight());mTextPaint.setColor(mTextColorChange);canvas.drawText(text,x,baseLine,mTextPaint);canvas.restore();}private void drawRight(Canvas canvas) {//绘制顶部渐变部分canvas.save();String text = getText().toString();float textWidth = mTextPaint.measureText(text);Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float textHeight = fontMetrics.descent - fontMetrics.ascent;float baseLine = (getHeight() + textHeight) / 2 - fontMetrics.descent;float x = (getWidth() - textWidth) / 2;float left = x + textWidth * (1 - mProgress);float right = x + textWidth;canvas.clipRect(left,0,right,getHeight());mTextPaint.setColor(mTextColorChange);canvas.drawText(text,x,baseLine,mTextPaint);canvas.restore();//绘制底部不变部分canvas.save();right = x + textWidth * (1 - mProgress);canvas.clipRect(0,0,right,getHeight());mTextPaint.setColor(mTextColor);canvas.drawText(text,x,baseLine,mTextPaint);canvas.restore();}static int sp2px(float sp) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, Resources.getSystem().getDisplayMetrics());}}
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {if(positionOffset > 0){ColorChangeTextView left = mTabs.get(position);ColorChangeTextView right = mTabs.get(position + 1);left.setDirection(ColorChangeTextView.RIGHT);right.setDirection(ColorChangeTextView.LEFT);left.setProgress(1- positionOffset);right.setProgress(positionOffset);}}});
评论
