Android 自定义TextView实现文字渐变动画
jopen
9年前
先来看效果
第一种效果的代码如下,主要是结合Shader实现的
import android.content.Context; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Shader; import android.util.AttributeSet; import android.util.Log; import android.widget.TextView; public class GradientShaderTextView extends TextView { private LinearGradient mLinearGradient; private Matrix mGradientMatrix; private Paint mPaint; private int mViewWidth = 0; private int mTranslate = 0; private boolean mAnimating = true; private int delta = 15; public GradientShaderTextView(Context ctx) { this(ctx,null); } public GradientShaderTextView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mViewWidth == 0) { mViewWidth = getMeasuredWidth(); if (mViewWidth > 0) { mPaint = getPaint(); String text = getText().toString(); // float textWidth = mPaint.measureText(text); int size; if(text.length()>0) { size = mViewWidth*2/text.length(); }else{ size = mViewWidth; } mLinearGradient = new LinearGradient(-size, 0, 0, 0, new int[] { 0x33ffffff, 0xffffffff, 0x33ffffff }, new float[] { 0, 0.5f, 1 }, Shader.TileMode.CLAMP); //边缘融合 mPaint.setShader(mLinearGradient); mGradientMatrix = new Matrix(); } } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int length = Math.max(length(), 1); if (mAnimating && mGradientMatrix != null) { float mTextWidth = getPaint().measureText(getText().toString()); mTranslate += delta; if (mTranslate > mTextWidth+1 || mTranslate<1) { delta = -delta; } mGradientMatrix.setTranslate(mTranslate, 0); mLinearGradient.setLocalMatrix(mGradientMatrix); postInvalidateDelayed(30); } } }
第二种效果
import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.view.ActionMode; import android.view.View; import android.widget.TextView; public class KTVTextView extends View { private Paint mPaint; private int delta = 15; private float mTextHeight; private float mTextWidth; private PorterDuffXfermode xformode; private String mText = "你是我生命里的一首歌"; public KTVTextView(Context ctx) { this(ctx,null); } public KTVTextView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public KTVTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); xformode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); initViewAndDatas(); setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { postIndex = 0; postInvalidate(); } }); } public void initViewAndDatas() { mPaint.setColor(Color.CYAN); mPaint.setTextSize(40.0f); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setXfermode(null); mPaint.setTextAlign(Paint.Align.LEFT); Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); mTextHeight = fontMetrics.bottom-fontMetrics.descent-fontMetrics.ascent; mTextWidth = mPaint.measureText(mText); //文字精确高度 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //super.onMeasure(widthMeasureSpec, heightMeasureSpec); int mWidth; int mHeight; /** * 设置宽度 */ int specMode = MeasureSpec.getMode(widthMeasureSpec); int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate { mWidth = specSize; } else { // 由图片决定的宽 int desireByImg = getPaddingLeft() + getPaddingRight() + 380; if (specMode == MeasureSpec.AT_MOST)// wrap_content { mWidth = Math.min(desireByImg, specSize); } else mWidth = desireByImg; } /*** * 设置高度 */ specMode = MeasureSpec.getMode(heightMeasureSpec); specSize = MeasureSpec.getSize(heightMeasureSpec); if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate { mHeight = specSize; } else { int desire = getPaddingTop() + getPaddingBottom() + 80; if (specMode == MeasureSpec.AT_MOST)// wrap_content { mHeight = Math.min(desire, specSize); } else { mHeight = desire; } } setMeasuredDimension((int) mWidth, (int) mHeight); } private int postIndex; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int contentWidth = getWidth() - getPaddingLeft() - getPaddingRight(); int contentHeight = getHeight() - getPaddingTop() - getPaddingBottom(); Bitmap srcBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888); Canvas srcCanvas = new Canvas(srcBitmap); srcCanvas.drawText(mText, 0, getPaddingTop(), mPaint); mPaint.setXfermode(xformode); mPaint.setColor(Color.RED); RectF rectF = new RectF(0,0,postIndex,mTextHeight); srcCanvas.drawRect(rectF, mPaint); canvas.drawBitmap(srcBitmap,getPaddingLeft(),getPaddingTop(), null); initViewAndDatas(); if(postIndex<mTextWidth) { postIndex+=10; postInvalidateDelayed(30); } } }
注意:
-
文本绘制时必须和当前View保持同样的长宽尺寸,否则会出现文字变形问题
-
文本绘制的drawText(string,int x,int y,Paint paint);中的y值是基线位置
mTextHeight = fontMetrics.bottom-fontMetrics.descent-fontMetrics.ascent;//获得文本的高度
-
注意内容去的尺寸大小以及图片合成模式
-
注意LinearGradient的最后一个参数
-
自己去试试吧,我这些代码不够完善。