Shader与BitmapShader 笔记

31 阅读2分钟
public BitmapShader(Bitmap bitmap,TileMode titleX,TileMode tileY);
//TileMode.CLAMP:用边缘颜色来填充多余空间
//TileMode.REPEAT:用重复图像来填充多余空间
//TileMode.MIRROR: 用镜像来填充多余空间

//填充顺序,先填充竖向然后再填充横向

来看一个小例子:

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

        }

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

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


我自己的理解,上面有三个比较关键canvas1,paint,canvas,这三者的角色就好比是一个版画

canvas1好比一个无形的需要印染的图案,如果图案想要1:1的印在canvas上,需要设置和canvas宽高相同,不然就会出现BitmapShader的多余填充效果, Canvas canvas1 = new Canvas(mBitmapBG);这里其实创建的是一个空白图层,没有绘制到canvas上,所以对于我们也是不可见的。

paint就好比是刻板,把canvas1对应位置的图案冲压到canvas。

canvas就好比作画的纸,最终呈现在用户视野里

在实际使用中,我们可以来实现圆角头像或使用bitmapShader.setLocalMatrix来对原图进行缩放等效果。

有趣的放大镜效果


public class TelescopeView extends View {
    private Bitmap bitmap;
    private ShapeDrawable drawable;
    // 放大镜的半径
    private static final int RADIUS = 80;
    // 放大倍数
    private static final int FACTOR = 3;
    private final Matrix matrix = new Matrix();
    public TelescopeView(Context context) {
        super(context);
        init();
    }
    public TelescopeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public TelescopeView(Context context, AttributeSet attrs, int defStyle) {

        super(context, attrs, defStyle);
        init();
    }
    private void init() {
        setLayerType(LAYER_TYPE_SOFTWARE, null);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        // 这个位置表示的是绘制 Shader 的起始位置
        matrix.setTranslate(RADIUS - x * FACTOR, RADIUS - y * FACTOR);
        drawable.getPaint().getShader().setLocalMatrix(matrix);
        drawable.setBounds(x - RADIUS, y - RADIUS, x + RADIUS, y + RADIUS);
        invalidate();
        return true;
    }
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap == null) {
            Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.
                    drawable.test1);
            bitmap = Bitmap.createScaledBitmap(bmp, getWidth(), getHeight(),
                    false);
            BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap
                    (bitmap,
                            bitmap.getWidth() * FACTOR, bitmap.getHeight() * FACTOR,
                            true),
                    Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            drawable = new ShapeDrawable(new OvalShape());
            drawable.getPaint().setShader(shader);
        }
        canvas.drawBitmap(bitmap, 0, 0, null);
        drawable.draw(canvas);
    }
}