当前位置 博文首页 > 启舰:自定义控件三部曲之绘图篇(十七)——为Bitmap添加阴影并

    启舰:自定义控件三部曲之绘图篇(十七)——为Bitmap添加阴影并

    作者:[db:作者] 时间:2021-06-30 15:32

    前言:再重复一遍我很喜欢的一句话,送给大家:迷茫,本就是青春该有的样子 ,但不要让未来的你,讨厌现在的自己

    系列文章:

    Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268

    上篇给大家讲解了如何控件添加阴影效果,但是在为Bitmap图片添加阴影时,却没办法添加具有指定颜色的阴影,这篇我们就来使用自定义的控件及自定义属性来初步封装下控件。前方高能预警——本篇内容涉及内容较多,难度较大,需要多加思考。

    ###一、使用BlurMaskFilter为图片构造定色阴影效果
    上面我们讲了通过setShadowLayer为图片添加阴影效果,但是图片的的阴影是用原图形的副本加上边缘发光效果组成的。我们怎么能给图片添加一个灰色的阴影呢?
    我们来分析一下setShadowLayer的阴影形成过程(假定阴影画笔是灰色),对于文字和图形,它首先产生一个跟原型一样的灰色副本。然后对这个灰色副本应用BlurMaskFilter,使其内外发光;这样就形成了所谓的阴影!当然最后再偏移一段距离。
    所以,我们要给图片添加灰色阴影效果,所以我们能不能仿一下这个过程:先绘制一个跟图片一样大小的灰色图形,然后给这个灰色图形应用BlurMaskFilter使其内外发光,然后偏移原图形绘制出来,不就可以了么
    所以,这里涉及到三个点:

    • 绘制出一个一样大小的灰色图形
    • 对灰色图形应用BlurMaskFilter使其内外发光
    • 偏移原图形一段距离绘制出来

    下面我们就通过例子来一步步看是怎么实现出来的吧
    ####1、绘制出一个一样大小的灰色图像
    首先,我们来看怎么能绘出一个指定Bitmap所对应的灰色图像。我们知道canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)中的paint的画笔颜色对画出来的bitmap是没有任何影响的,因为原来Bitmap长什么样,无论你画笔是什么颜色,画出来的图片还是跟原图片长的一样。所以如果我们需要画一张对应的灰色图像,我们需要新建一个一样大小的空白图,但是新图片的透明度要与原图片保持一致。所以如何从原图片中抽出Alpha值成为了关键。即我们只需要创建一个与原图片一样大小且Alpha相同的图片即可。
    其实Bitmap中已经存在抽取出只具有Alpha值图片的函数:

    public Bitmap extractAlpha();
    

    extraAlpha()函数的功能是:新建一张空白图片,图片具有与原图片一样的Alpha值,这个新建的Bitmap做为结果返回。这个空白图片中每个像素都具有与原图片一样的Alpha值,而且具体的颜色时,只有在使用canvas.drawBitmap绘制时,由传入的paint的颜色指定。
    所以总结来讲:

    • extractAlpha()新建一张仅具有Alpha值的空白图像
    • 这张图像的颜色,是由canvas.drawBitmap时的画笔指定的。

    (1)、extractAlpha()使用示例
    下面,我们就用个例子先来看下extractAlpha()函数的用法
    我们拿一张图片来做试验,下面这张PNG图片中,一只小猫和一只小狗,其余地方都是透明色。
    这里写图片描述
    下面我们分别利用extractAlpha()画出它对应的红色和绿色的阴影图
    在这里插入图片描述
    对应的代码为:

    public class ExtractAlphaView extends View {
        private Paint mPaint;
        private Bitmap mBitmap,mAlphaBmp;
        public ExtractAlphaView(Context context) {
            super(context);
            init();
        }
    
        public ExtractAlphaView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public ExtractAlphaView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        private void init(){
            setLayerType(LAYER_TYPE_SOFTWARE,null);
            mPaint = new Paint();
            mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.blog12);
            mAlphaBmp = mBitmap.extractAlpha();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            int width = 200;
            int height = width * mAlphaBmp.getHeight()/mAlphaBmp.getWidth();
             mPaint.setColor(Color.RED);
            canvas.drawBitmap(mAlphaBmp,null,new Rect(0,0,width,height),mPaint);
    
            mPaint.setColor(Color.GREEN);
            canvas.drawBitmap(mAlphaBmp,null,new Rect(0,height,width,2*height),mPaint);
        }
    }
    

    首先看init函数:

    private void init(){
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        mPaint = new Paint();
        mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.blog12);
        mAlphaBmp = mBitmap.extractAlpha();
    }
    

    首先是禁用硬件加速,这基本上是我们做自定义控件的标配!为了防止功能不好用,记得每次都加上这个函数!然后是利用extratAlpha()来生成仅具有透明度的空白图像。
    最后看OnDraw函数:

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    
        int width = 200;
        int height = width * mAlphaBmp.getHeight()/mAlphaBmp.getWidth();
        mPaint.setColor(Color.RED);
        canvas.drawBitmap(mAlphaBmp,null,new Rect(0,0,width,height),mPaint);
    
        mPaint.setColor(Color.GREEN);
        canvas.drawBitmap(mAlphaBmp,null,new Rect(0,height,width,2*height),mPaint);
    }
    

    这里分别将画笔的颜色设置为红色和绿色,然后两次把mAlphaBmp画出来。上面我们已经提到,在画仅具有透明度的空白图像时,图像的颜色是由画笔颜色指定的。所以从效果图中也可以看出画出来的图像分别红色的绿色的。
    这就是Bitmpa.extraAlpha()的用法!
    ####2、对灰色图形应用BlurMaskFilter使其内外发光
    在第一步完成了之后,我们进行第二步,将阴影添加内外发光效果。就形成了阴影的模样。
    代码很简单,只需要使用Paint.setMaskFilter函数添加发光效果即可,代码如下:

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    
        int width = 200;
        int height = width * mAlphaBmp.getHeight()/mAlphaBmp.getWidth();
        mPaint.setColor(Color.RED);
        mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
        canvas.drawBitmap(mAlphaBmp,null,new Rect(0,0,width,height),mPaint);
    
        mPaint.setColor(Color.GREEN);
        canvas.drawBitmap(mAlphaBmp,null,new Rect(0,height,width,2*height),mPaint);
    }
    

    明显可以看出这里只添加了一行代码:mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));就是添加内外发光效果,难度不大,不再细讲。
    ####3、偏移原图形一段距离绘制出来
    这段比较简单了,只需要先把阴影画出来,然后再把原图像盖上去,但需要注意的是,阴影需要相对原图像偏移一段距离。完整代码如下:

    public class ExtractAlphaView extends View {
        private Paint mPaint;
        private Bitmap mBitmap,mAlphaBmp;
        public ExtractAlphaView(Context context) {
            super(context);
            init();
        }
    
        public ExtractAlphaView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public ExtractAlphaView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        private void init(){
            setLayerType(LAYER_TYPE_SOFTWARE,null);
            mPaint = new Paint();
            mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.blog12);
            mAlphaBmp = mBitmap.extractAlpha();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            int width = 200;
            int height = width * mAlphaBmp.getHeight()/mAlphaBmp.getWidth();
    
            //绘制阴影
            mPaint.setColor(Color.RED);
            mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));
            canvas.drawBitmap(mAlphaBmp,null,new Rect(10,10,width,height),mPaint);
            mPaint.setColor(Color.GREEN);
            canvas.drawBitmap(mAlphaBmp,null,new Rect(10,height+10,width,2*height),mPaint);
    
            //绘制原图像
            mPaint.setMaskFilter(null);
            canvas.drawBitmap(mBitmap,null,new Rect(0,0,width,height)