欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android进阶(4)Paint实现几种效果

程序员文章站 2024-03-24 12:20:10
...

1.线性渐变 文字闪烁效果(聚光灯效果)

  • 关于Shader.TileMode.CLAMP

    • CLAMP 如果当前的图片无法填满容器,则其在横/纵向上将最后一个像素拉伸

    • REPEAT 如果当前的图片无法填满容器,则其在横/纵向上复制一个去填充

    • MIRROR 如果当前的图片无法填满容器,则其在横/纵向上复制一个镜像去填充,需要注意的是横向上是左右镜像,纵向上是上下镜像

        public class LinearGradientTextView extends AppCompatTextView {
      
            private Matrix mMatrix;
            private int mTranslateX = 10;//每次的平移量
        	private int mCurrentX;//当前平移的位置
            private LinearGradient mGradient;
            private float mTextSize, mTextLength;
        
            public LinearGradientTextView(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        
        	//在View的layout方法中调用
            @Override
            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                super.onSizeChanged(w, h, oldw, oldh);
                mTextSize = (mTextLength = getPaint().measureText(getText().toString().trim())) / getText().toString().length();
        		
        		//因为需要的是聚光灯效果,开始和结束的颜色都应该和文本的颜色一致,中间的颜色用白色,
        		//参数可以是多个,不一定是三个,根据需要的效果来确定
                mGradient = new LinearGradient(-mTextSize * 3, 0, 0, 0,
                        new int[]{Color.GRAY, Color.WHITE, Color.GRAY}, null, Shader.TileMode.CLAMP);
                mMatrix = new Matrix();
                getPaint().setShader(mGradient);
            }
        
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                mCurrentX += mTranslateX;
                if (mCurrentX > mTextLength + mTextSize * 3 || mCurrentX < 0) {
                    mTranslateX = -mTranslateX;
                }
      
        		//矩阵的平移函数
                mMatrix.postTranslate(mTranslateX, 0);
                mGradient.setLocalMatrix(mMatrix);
                postInvalidateDelayed(10);
            }
        }
      

2.扫描式渐变 雷达扫描效果

public class RadarView extends View {

    private int mWidth;
    private int mHeight;
    private int mDiameter;
    private Paint mCirclePaint;

    private Paint mRadarPaint;
    private Matrix mMatrix;

    public RadarView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mCirclePaint = new Paint();
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setStrokeWidth(5);

        mRadarPaint = new Paint();
        mRadarPaint.setStyle(Paint.Style.FILL);

        mMatrix = new Matrix();
        mMatrix.postRotate(0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mWidth == 0 && mHeight == 0) {
			//此处减5的原因是画线是向外拓展,半径减5后加上画笔的宽度刚好到达布局边界
            mDiameter = Math.min(mWidth = getMeasuredHeight(), mHeight = getMeasuredWidth()) - 5;
            SweepGradient shader = new SweepGradient(mWidth >> 1, mHeight >> 1, Color.BLUE, Color.GRAY);
            mRadarPaint.setShader(shader);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawRoundRect((mWidth - mDiameter) >> 1, (mHeight - mDiameter) >> 1, 
				mWidth - ((mWidth - mDiameter) >> 1), mHeight - ((mHeight - mDiameter) >> 1), 
				mWidth >> 1, mHeight >> 1, mCirclePaint);

        canvas.setMatrix(mMatrix);
        canvas.drawCircle(mWidth >> 1, mHeight >> 1, mDiameter >> 1, mRadarPaint);
        postInvalidateDelayed(30);

		//矩阵的旋转函数,注意此处需要指明旋转的中心点,否则的话会按照0,0作为原点旋转
        mMatrix.postRotate(2, mWidth >> 1, mHeight >> 1);
    }

}

3.颜色矩阵运算

矩阵的运算 Amn * Bnl = Cml

[012431027510010][01101]=[(00+11+22+40+31)(10+01+21+70+51)(10+01+01+10+01)]=[870] \begin{gathered} \begin{bmatrix} 0 &1&2&4&3 \\ 1 & 0&2&7&5 \\ 1 & 0&0&1&0 \end{bmatrix}* \quad \begin{bmatrix} 0 \\ 1 \\ 1 \\ 0 \\ 1 \end{bmatrix} = \quad \begin{bmatrix} (0*0+1*1+2*2+4*0+3*1) \\ (1*0+0*1+2*1+7*0+5*1) \\ (1*0+0*1+0*1+1*0+0*1)\end{bmatrix}= \begin{bmatrix} 8 \\ 7 \\ 0 \end{bmatrix} \quad \quad \end{gathered}

public class ChannelView extends View {

    private Bitmap mBitmap;
    private Paint mPaint;
    private Bitmap mTempBitmap;
    private ColorMatrixColorFilter filter;

    public ChannelView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.timg);
        mBitmap = Bitmap.createScaledBitmap(mBitmap, mBitmap.getWidth() >> 1, mBitmap.getHeight() >> 1, false);

        mTempBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight());

        //底片效果,就是用255减去原来的数值
        filter = new ColorMatrixColorFilter(new ColorMatrix(new float[]{
                -1, 0, 0, 0, 255,
                0, -1, 0, 0, 255,
                0, 0, -1, 0, 255,
                0, 0, 0, 1, 0
        }));
   
        //颜色增强,就是原来的倍数
        filter = new ColorMatrixColorFilter(new ColorMatrix(new float[]{
                1.3f, 0, 0, 0, 0,
                0, 1.3f, 0, 0, 0,
                0, 0, 1.3f, 0, 0,
                0, 0, 0, 1.3f, 0
        }));
        //黑白  同一个通道中R+G+B=1且三个通道相同即可
        filter = new ColorMatrixColorFilter(new ColorMatrix(new float[]{
                0.2f, 0.7f, 0.1f, 0, 0,
                0.2f, 0.7f, 0.1f, 0, 0,
                0.2f, 0.7f, 0.1f, 0, 0,
                0, 0, 0, 1, 0
        }));
        //复古效果
        filter = new ColorMatrixColorFilter(new ColorMatrix(new float[]{
                1 / 2f, 1 / 2f, 1 / 2f, 0, 0,
                1 / 3f, 1 / 3f, 1 / 3f, 0, 0,
                1 / 4f, 1 / 4f, 1 / 4f, 0, 0,
                0, 0, 0, 1, 0
        }));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
        mPaint.setColorFilter(filter);
        canvas.drawBitmap(mTempBitmap, getMeasuredWidth() - mBitmap.getWidth(), 0, mPaint);
    }
}

4.Xfermode的使用

  • 关于PorterDuff.Mode
    • DST_IN 只在src和dst相交的地方绘制dst

    • DST_ATOP 只在src和dst相交的地方绘制dst,不相交的地方绘制src

    • DST_OUT 只在src和dst不相交的地方绘制dst

    • SRC_IN 只在src和dst相交的地方绘制src

    • SRC_ATOP 只在src和dst相交的地方绘制src,不相交的地方绘制dst

    • SRC_OUT 只在src和dst不相交的地方绘制src

        public class WaveView extends View {
      
            private Bitmap mSrc, mDest;
            private Paint mPaint;
            private PorterDuffXfermode mXfermode;
            private int currentX;
        
            public WaveView(Context context, @Nullable AttributeSet attrs) {
                super(context, attrs);
                mDest = BitmapFactory.decodeResource(getResources(), R.mipmap.wav);//波浪图
                mSrc = BitmapFactory.decodeResource(getResources(), R.mipmap.circle);//圆形
                mPaint = new Paint();
                mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
            }
        
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                if (mSrc.getWidth() > getMeasuredWidth() || mSrc.getHeight() > getMeasuredHeight()) {
                    mSrc = createScaledBitmap(mSrc, getMeasuredWidth(), getMeasuredWidth(), false);
                }
            }
        
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
        		//首先保存当前的状态信息
                int i = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
        		//画目标图
                canvas.drawBitmap(mDest, currentX, 0, mPaint);
                mPaint.setXfermode(mXfermode);
        		//话源图
                canvas.drawBitmap(mSrc, 0, 0, mPaint);
        		//清理混合模式
                mPaint.setXfermode(null);
        		//还原状态信息
                canvas.restoreToCount(i);
      
                currentX -= 20;
                if (Math.abs(currentX) > mDest.getWidth() - mSrc.getWidth()) {
                    currentX = 0;
                }
                postInvalidateDelayed(10);
            }
        }