Android自定义控件开发入门与实战(10)Shader

Shader与BitmapShader

本篇blog内容和hencoder学习自定义view(1)部分内容相似,有些知识就直接跳过了。

Shader是着色器,是用来给空白图形上色的。
当设置了Shader后,Paint就不会使用setColor或者setARGB里面的颜色了,而是直接使用Shader中的方案。

public Shader setShader(Shader shader)

Shader类只是一个基类,其中只有两个函数setLocalMatrix(Matrix localM)和getLocalMatrix(Matrix localM),用来设置坐标变换矩阵。有关设置矩阵的内容,这里就先略过。
Shader类下的几个派生类为:BitmapShader,ComposeShader,LinearGradient,RadialGradient,SweepGradient

BitmapShader

public BitmapShader(Bitmap bitmap,TileMode tileX,TileMode tileY)

TileMode的取值如下:

  • TileMode.CLAMP:用边缘颜色来填充多余空间
  • TileMode.REPEAT:重复原图像来填充多余空间
  • TileMode.MIRROR:重复使用镜像模式的图像来填充多余空间

这里就不再写介绍了,注意:填充空间是先填充Y轴,再填充X轴。

示例:望远镜效果:
如果我们用一个setShader的paint去在一个控件上绘制一个图形,并且我们绘制的图形大小 小于 控件的大小,那这样只会显示绘制出的区域,别的区域已经绘制好了但是并不显示,我们根据该原理来制作一个望远镜效果:
在这里插入图片描述
就是在点击时产生一个圆形的望远镜,然后可以看到图片

首先我们先初始化背景图片和画笔:

 public TelescopeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_telescope);
    }

接着我们重写onTouchEvent方法,当点击时记录坐标并重绘界面, 不点击时将坐标置为默认值。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDx = (int) event.getX();
                mDy = (int) event.getY();
                postInvalidate();
                return true;
            case MotionEvent.ACTION_MOVE:
                mDx = (int) event.getX();
                mDy = (int) event.getY();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mDx = -1;
                mDy = -1;
                break;

        }
        postInvalidate();
        return super.onTouchEvent(event);
    }

最后重写onDraw函数
这里分成两步。第一步将图片mbitmapBG缩放到控件大小,以完全覆盖控件,否则就会使用BitmapShader的填充模式。
这里先新建一张空白的位图cavasbg,这张位图的大小与控件大小一致,然后对背景位图进行拉伸,画到这张空白的位图上。
第二步,在mDx、mDy都不是-1时,将新建的mBitmapBG作为BitmapShader设置给Paint,然后在手指所在的位置画圆,把圆圈部分的图像显示出来。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mBitmapBG == null) {
            mBitmapBG = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvasbg = new Canvas(mBitmapBG);
            canvasbg.drawBitmap(mBitmap, null, new Rect(0, 0, getWidth(), getHeight()), mPaint);
        }

        if (mDx != -1 && mDy != -1) {
            mPaint.setShader(new BitmapShader(mBitmapBG, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
            canvas.drawCircle(mDx, mDy, 150, mPaint);
        }
    }

下面的示例来讲解生成不规则的头像。
首先初始化bitmap:

 public AvatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.avator_xizuka);
        mPaint = new Paint();
        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    }

接下来,将BitmapShader缩放到与控件的宽、高一致(setScale),由于我们要画的是一幅圆形图像,所以必须将图像缩放成一个正方形,只要正方形的边长与控件的宽度一致即可。

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Matrix matrix = new Matrix();
        float scale = (float) getWidth() / mBitmap.getWidth();
        matrix.setScale(scale, scale);
        mBitmapShader.setLocalMatrix(matrix);
        mPaint.setShader(mBitmapShader);

        float half = getWidth() / 2;
        canvas.drawCircle(half, half, getWidth() / 2, mPaint);
    }

在这里插入图片描述
同样是缩放BitmapShader,这里使用Matrix进行缩放,而前面的望远镜示例则是通过新建一张位图来进行缩放,这两种缩放方式都可用。

在缩放BitmapShader以后,在控件的正中央画一个圆形,显示出一副圆形区域的图像。这就是我们想要的圆形头像。

Shader之LinearGradient

通过LinearGradient可以实现渐变的效果
下面是构造函数

public LinearGradient(float x0,float y0,float x1,float y1,int color0,int color1,TileMode tile)

其中(x0,y0) (x1,y1)分别表示起点、终点坐标。color0、color1表示起点终点颜色,tile和BitmapShader一样。
其中color用0xAARRGGBB显示,AA不能少。
第二个构造函数为:

public LinearGradient(float x0,float y0,float x1,float y1,int colors[],float positions[],TileMode tile)

其中colors[]用于指定颜色值数值,同样用0xAARRGGBB形式。
positions[]与渐变的颜色相对应,取值是0-1的Float类型数据。表示color中的每种颜色在渐变线中百分比的位置。

示例:闪光文字效果
这里做一个跑马灯式的文字渐变效果。
原理是做一个渐变的图像,和一段文字,然后渐变头像在文字上进行移动,使文字发光,变换颜色。
该渐变图像移动两个文字长度的距离。

首先我们让View继承自TextView,因为TextView本身可以绘制文字,不需要我们自己处理,所以这样方便一点。

  public ShimmerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mPaint = getPaint();
        int length = (int) mPaint.measureText(getText().toString());
        createAnim(length);
        createLinearGradient(length);
    }

接下里就是创建动画,动画让LinearGradient去移动,所以动画的起始到终止值应该是(0,2*text_Length),每次有新进度则重绘文字:

private void createAnim(int length) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 2 * length);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mDx = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setDuration(2000);
        valueAnimator.start();
    }

然后创建LinearGradient,其大小和TextView大小一样

 private void createLinearGradient(int length) {
        mLinearGradient = new LinearGradient(-length, 0, 0, 0, new int[]{getCurrentTextColor(), 0xff00ff00, getCurrentTextColor()},
                new float[]{0, 0.5f, 1}, Shader.TileMode.CLAMP);
    }

最后重写onDraw方法,根据setTranslate(mDx,0)来让其移动:

    @Override
    protected void onDraw(Canvas canvas) {
        Matrix matrix = new Matrix();
        matrix.setTranslate(mDx,0);
        mLinearGradient.setLocalMatrix(matrix);
        mPaint.setShader(mLinearGradient);

        super.onDraw(canvas);
    }

效果如下:
在这里插入图片描述

Shader之RadialGradient

RadialGradient就是放射源式的渐变,从一个中心点发散。
双色渐变构造函数如下:

RadialGradient(float centerX,float centerY,float radius,int centerColor,int edgeColor,Shader.TileMode tileMode)

其中 centerColor表示渐变的起始颜色,edgeColor表示渐变的边缘颜色
两个颜色都必须用0xAARRGGBB来表示。
其他的没什么必要介绍

多色渐变构造函数如下:

RadialGradient(float X,float centerY,float radius,int[] colors,float[] stops,Shader.TileMode tileMode)

其中 int[] colors表示颜色数组
而 float[] stops表示colors颜色在渐变线上的范围,取值0-1。

示例什么的用的少,之前另一篇Blog也讲过,这里就不再赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值