美文网首页Android开发经验谈Android开发
Android自定义控件之不规则形状图片

Android自定义控件之不规则形状图片

作者: 书柜里的松鼠 | 来源:发表于2018-05-23 10:39 被阅读472次

    先看下效果。


    Screenshot_2018-05-18-14-33-44-159_net.codepig.customviewdemo.png
    使用遮罩就可以实现不规则形状的图片。

    本例中使用的图片是:


    android.jpg

    遮罩图片则长这样:


    mask.jpg
    1.先扩展一个ImageView
    package net.codepig.customviewdemo.view;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.support.v7.widget.AppCompatImageView;
    
    /**
     * 遮罩图片
     */
    public class MaskImage extends AppCompatImageView {
        public MaskImage(Context context, AttributeSet attrs) {
            super(context, attrs);
            
        }
    }
    
    2.添加定义属性

    在attrs.xml中添加imagemask两个属性,分别代表的是需要显示的图片和遮罩。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="MaskImage">
            <attr name="image" format="integer" />
            <attr name="mask" format="integer" />
        </declare-styleable>
    </resources>
    
    3.在布局中使用
    <net.codepig.customviewdemo.view.MaskImage
            android:id="@+id/maskImage"
            android:scaleType="fitXY"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            MaskImage:image="@drawable/android"
            MaskImage:mask="@drawable/mask" />
    

    这里头的androidmask就是前面说到的两个图片。(mask必须是含alpha通道的背景透明图片哦)

    4.接下来就要通过Paint.setXfermode方法进行绘制

    Paint.setXfermode方法会根据透明度对两张图片进行合并,这样就实现了遮罩的效果。
    一下是具体代码:

    package net.codepig.customviewdemo.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    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.support.v7.widget.AppCompatImageView;
    
    import net.codepig.customviewdemo.R;
    
    /**
     * 遮罩图片
     */
    package net.codepig.customviewdemo.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    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.support.v7.widget.AppCompatImageView;
    
    import net.codepig.customviewdemo.R;
    
    /**
     * 遮罩图片
     */
    public class MaskImage extends AppCompatImageView {
        private int mImageSource = 0;
        private int mMaskSource = 0;
    //    private RuntimeException mException;
        public MaskImage(Context context, AttributeSet attrs) {
            super(context, attrs);
            //从参数获取对应的图片资源
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaskImage, 0, 0);
            mImageSource = a.getResourceId(R.styleable.MaskImage_image, 0);
            mMaskSource = a.getResourceId(R.styleable.MaskImage_mask, 0);
    
            //获取图片的bitmap
            Bitmap original = BitmapFactory.decodeResource(getResources(), mImageSource);
            //获取遮罩的bitmap
            Bitmap mask = BitmapFactory.decodeResource(getResources(), mMaskSource);
            //根据透明度创建一个新的bitmap,需要注意的是这里的第三个参数的值Bitmap.Config.ARGB_8888表示支持32位图片,也就是支持透明通道。
            Bitmap result = Bitmap.createBitmap(original.getWidth(), original.getHeight(), Bitmap.Config.ARGB_8888);
            //将遮罩层的图片放到画布中
            Canvas mCanvas = new Canvas(result);
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            //设置图层混合模式
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            //一次绘制图层
            mCanvas.drawBitmap(original, 0, 0, null);
            mCanvas.drawBitmap(mask, 0, 0, paint);
            paint.setXfermode(null);
            setImageBitmap(result);
            setScaleType(ScaleType.CENTER);
            //释放掉图片资源
            a.recycle();
        }
    }
    
    5.完善图片尺寸问题

    以上的代码还有一个小问题,当遮罩图片和原图片不是一样尺寸时会出现以下状态。


    Screenshot_2018-05-18-15-53-36-102_net.codepig.customviewdemo.png

    那么为了完美起见,我们需要对图片进行一下缩放。
    这里使用原图片作为基准,使用Matrix进行缩放,绘制代码调整如下:

    //获取图片的bitmap
            Bitmap original = BitmapFactory.decodeResource(getResources(), mImageSource);
            Log.d("LOGCAT","pic size:"+original.getWidth()+"-"+original.getHeight());
            //获取遮罩的bitmap
            Bitmap mask = BitmapFactory.decodeResource(getResources(), mMaskSource);
            Log.d("LOGCAT","mask size:"+mask.getWidth()+"-"+mask.getHeight());
            //根据透明度创建一个新的bitmap,需要注意的是这里的第三个参数的值Bitmap.Config.ARGB_8888表示支持32位图片,也就是支持透明通道。
            Bitmap result = Bitmap.createBitmap(original.getWidth(), original.getHeight(), Bitmap.Config.ARGB_8888);
            //将遮罩层的图片放到画布中
            Canvas mCanvas = new Canvas(result);
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            //设置图层混合模式
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            //一次绘制图层
            mCanvas.drawBitmap(original, 0, 0, null);
            //计算mask的绘制比例
            Matrix mMatrix = new Matrix();
            //这里有个小坑,别忘了getWidth和getHeight的值转为float,不然算出来的也是整数。
            mMatrix.setScale((float)original.getWidth() / (float)mask.getWidth(), (float)original.getHeight() / (float)mask.getHeight());
            mCanvas.drawBitmap(mask, mMatrix, paint);
            paint.setXfermode(null);
            setImageBitmap(result);
            setScaleType(ScaleType.CENTER);
            //释放掉图片资源
            a.recycle();
    

    相关github项目地址:
    https://github.com/codeqian/customViewDemo/blob/master/app/src/main/java/net/codepig/customviewdemo/view/MaskImage.java

    相关文章

      网友评论

        本文标题:Android自定义控件之不规则形状图片

        本文链接:https://www.haomeiwen.com/subject/bwowdftx.html