zoukankan      html  css  js  c++  java
  • Android 遮罩层效果

    (用别人的代码进行分析) 不知道在开发中有没有经常使用到这种效果,所谓的遮罩层就是给一张图片不是我们想要的形状,这个时候我们就可以使用遮罩效果把这个图片变成我们想要的形状,一般使用最多就是圆形的效果,如下图:

    上面这个图片是圆形的,而我们这个原图是正方形的,所以我们可能就需要这么一个遮罩的效果使它变为圆形,这种一般就是我们图片从网络上获取的,形状不是由我们自己定的,所以才会加上这么一个效果,看下面的原图:

    这个是一个正方形的,那么要弄这么一个圆形,我们还需要一个圆形全黑的图片,如下

    就是这个图片,其实简单的来说就是两个图片相结合,只显示被黑色图片覆盖的区域,外面的区域就不显示,这样就成一个圆形的图片了(上面的图片都是采用从别的应用程序来的),其实这个主要的技术还是涉及到了PorterDuffXfermode类的使用方法,

    PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

    上面就是PorterDuffXfermode类的创建,那么里面的参数PorterDuff.Mode.SRC_IN其实有很多中情况,好像有达到16中情况,下面介绍一下常用的:

    PorterDuff.Mode.SRC_IN:取两层绘制交集。显示上层。就是如果上面两张图片相叠,那么取这两张图片的交集而且显示的是上层那种图片

    PorterDuff.Mode.DST_IN:  取两层绘制交集。显示下层。

    其它可以到网上可以查询得到,这两个用得也比较多。下面还有一张图片是外围那层图片的效果

    好,我们现在来看看这个代码是如何来写的

    package com.example.myimageview;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class MyImageView extends View {
        
        private Context context;
        
        private Bitmap bitmapBorder;
        private Bitmap bitmapMask;
        private Paint paint;
        private PorterDuffXfermode xfermode;
        
        private Bitmap bitmap;
        
        private int _width;
        private int _height;
    
        public MyImageView(Context context){
            this(context, null);
        }
    
        public MyImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.context = context;
            
            bitmapBorder = decodeBitmap(R.drawable.border);
            bitmapMask = decodeBitmap(R.drawable.mask);
            
            _width = bitmapBorder.getWidth();
            _height = bitmapBorder.getHeight();
            
            paint = new Paint();
            xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        }
    
        public MyImageView(Context context, AttributeSet attrs, int defStyle) {
            this(context, attrs);
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(_width, _height);
        }
        
        private Bitmap decodeBitmap(int resId) {
            return BitmapFactory.decodeResource(context.getResources(), resId);
        }
        
        public void setResourseId(int resourseId) {
            bitmap = decodeBitmap(resourseId);
            invalidate();
        }
        
        public void setResourseBitmap(Bitmap bitmap){
            this.bitmap = bitmap;
            invalidate();
        }
        
        @Override
        protected void onDraw(Canvas canvas) {
            if(bitmap == null){
                return;
            }
            canvas.drawBitmap(bitmapBorder, 0, 0, paint);
            int saveFlags = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
            canvas.saveLayer(0, 0, _width, _height, null, saveFlags);
            canvas.drawBitmap(bitmapMask, 0, 0, paint);
            paint.setXfermode(xfermode);
            int left = _width/2 - bitmap.getWidth() /2;
            int top = _height/2 - bitmap.getHeight()/2;
            canvas.drawBitmap(bitmap, left, top, paint);
            paint.setXfermode(null);
            canvas.restore();
        }
    }

    下面我们来分析一下代码的结构:

    MyImageView是继承view的一个子类,在构造函数中我们看到设置两张图片bitmapBorder就是我上面贴出来的最下面外围的图片,bitmapMask就是那个全黑圆形的图片,_width和_height是bitmapBorder(外围那张图片的宽度和高度),因为那张图片是最大的我们需要定义这个view的大小所以需这个宽和高,下面

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(_width, _height);
        }

    就是使用宽和高来处理的,同时我们还看到了画笔Paint和PorterDuffXfermode创建,要说明一下这个PorterDuffXfermode对象是通过画笔Paint来设置的,下面有说明的

        public void setResourseId(int resourseId) {
            bitmap = decodeBitmap(resourseId);
            invalidate();
        }

    这个代码就是需要我们手动传入想要变为圆形的图片,这个是在Avtivity中设置就行,最主要的代码来看onDraw()方法里面的。

        @Override
        protected void onDraw(Canvas canvas) {
            if(bitmap == null){
                return;
            }
            canvas.drawBitmap(bitmapBorder, 0, 0, paint);
            int saveFlags = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
            canvas.saveLayer(0, 0, _width, _height, null, saveFlags);
            canvas.drawBitmap(bitmapMask, 0, 0, paint);
            paint.setXfermode(xfermode);
            int left = _width/2 - bitmap.getWidth() /2;
            int top = _height/2 - bitmap.getHeight()/2;
            canvas.drawBitmap(bitmap, left, top, paint);
            paint.setXfermode(null);
            canvas.restore();
        }

    我们来看有三个地方使用了canvas.drawBitmap这个方法,简单理解就是谁先那么该图片就显示在最下面,最后使用的drawBitmap()方法就显示在最上面

    canvas.saveLayer()方法和canvas.restore()是成对出现的,

    Canvas 在一般的情况下可以看作是一张画布,所有的绘图操作如drawBitmap, drawCircle都发生在这张画布上,这张画板还定义了一些属性比如Matrix,颜色等等。但是如果需要实现一些相对复杂的绘图操作,比如多层动 画,地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)。Canvas提供了图层(Layer)支持,缺省情况可以看作是只有一个图 层Layer。如果需要按层次来绘图,Android的Canvas可以使用SaveLayerXXX, Restore 来创建一些中间层,对于这些Layer是按照“栈结构“来管理的:   

     创建一个新的Layer到“栈”中,可以使用saveLayer, savaLayerAlpha, 从“栈”中推出一个Layer,可以使用restore,restoreToCount。但Layer入栈时,后续的DrawXXX操作都发生在这个 Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas上,在复制Layer到Canvas上时,可以指定Layer的 透明度(Layer),这是在创建Layer时指定的:public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags);

    具体点可以到http://blog.csdn.net/linghu_java/article/details/8939952这个网站了解一下。

    paint.setXfermode(xfermode);这个就是设置了画笔的效果了,left和top不用说了就是该图片要显示在中心的位置。canvas.drawBitmap(bitmap, left, top, paint);这个是最后那个canvas.drawBitmap方法,而且使用的PorterDuff.Mode.SRC_IN参数,表示的是取两层绘制交集。显示上层,那就是显示最后一张图片。

    其实从上面来看效果是不错的,但是在真正的应用中我们不难会发现有些图片可能很大,这个时候就需要我们对图片进行等比的放大效果

    http://bbs.csdn.net/topics/310218516这个网址就看到有介绍等比缩放图片的例子,我们来看下面的图片效果

    上面两张图对比,第一张就是原来的效果,第二张就是对图片进行等比的缩放效果,看看第二张图片代码的:

    package com.example.myimageview;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.RectF;
    import android.graphics.PorterDuff.Mode;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class itchqImageView extends View{
    
        private Bitmap bg;
        private Bitmap photo;
        
        private int bg_width;
        private int bg_height;
        public itchqImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
            init();
        }
        
        private void init(){
            bg=BitmapFactory.decodeResource(getResources(),R.drawable.mask);
            bg_width=bg.getWidth();
            bg_height=bg.getHeight();
        }
    
        public void setImageView(int imgId){
            photo=BitmapFactory.decodeResource(getResources(), imgId);
            scaleImage();
        }
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
            Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
            
            paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
            
            RectF rectf=new RectF(0,0,bg_width,bg_height);
            
            canvas.saveLayer(rectf, null, Canvas.ALL_SAVE_FLAG);
            canvas.drawBitmap(photo, 0,0, null);
            canvas.drawBitmap(bg, 0, 0,paint);
            canvas.restore();
        }
        
        private void scaleImage(){
            
            if(photo!=null){
                
                int widht=photo.getWidth();
                int height=photo.getHeight();
                
                int new_width=0;
                int new_height=0;
                
                if(widht!=height){
                    if(widht>height){
                        new_height=bg_height;
                        new_width=widht*new_height/height;
                    }else{
                        new_width=bg_width;
                        new_height=height*new_width/widht;
                    }
                }else{
                    new_width=bg_width;
                    new_height=bg_height;
                }
                photo = Bitmap.createScaledBitmap(photo, new_width, new_height, true);
            }
        }
        
    
    }
    scaleImage()这个方法里面就是对图片进行等比的缩放效果,缩放的大小就和我们全黑色的图片大小一样(这里我们原来外面圆形效果去掉了,就是上面第三张全白色的图片)
    如果图片不是正方形的我们就需要进行判断对比,最后得出的宽和高就是我们要等比缩放的大小。
  • 相关阅读:
    linux 解压tgz 文件指令
    shell 脚本没有执行权限 报错 bash: ./myshell.sh: Permission denied
    linux 启动solr 报错 Your Max Processes Limit is currently 31202. It should be set to 65000 to avoid operational disruption.
    远程查询批量导入数据
    修改 MZTreeView 赋权节点父节点选中子节点自动选中的问题
    关于乱码的问题解决记录
    我的网站优化之路
    对设计及重构的一点反思
    我的五年岁月
    奔三的路上
  • 原文地址:https://www.cnblogs.com/itchq/p/3938506.html
Copyright © 2011-2022 走看看