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);      }    }    }


注意:

  1. 文本绘制时必须和当前View保持同样的长宽尺寸,否则会出现文字变形问题

  2. 文本绘制的drawText(string,int x,int y,Paint paint);中的y值是基线位置

  3. mTextHeight = fontMetrics.bottom-fontMetrics.descent-fontMetrics.ascent;//获得文本的高度
  4. 注意内容去的尺寸大小以及图片合成模式

  5. 注意LinearGradient的最后一个参数

  6. 自己去试试吧,我这些代码不够完善。

来自: http://my.oschina.net/ososchina/blog/603274