Android中自定义视图View之---进阶篇(Canvas的使用)
一、前言
那么今天,我们继续来看一篇关于Android中的UI篇,如何自定义视图View的进阶篇,关于前奏篇之前已经写过了,在这篇文章中我主要介绍了自定义View的一些基础知识,讲解了Paint,Canvas,Path,渐变色等技术。那么隔了半年的时间,我们今天再次看一下如何在上一个层次去使用Canvas自定义更多的我们想要的特效呢?说道这里,我还想多讲两句,就是Android中UI知识点还是很多很高深的,如果你对UI技术了解的非常透彻,那么待遇也是很不错的,现在可以看到一些公司在找Android高级UI工程师,就是叫你去做一些酷炫的UI,同时对性能方面也是要了解很多的,因为我们知道酷炫的UI动画什么的,其实如果处理不好会给整个程序造成很大的性能问题。所以本人对Android中的UI和逆向领域非常感兴趣的。
二、知识点&实现的效果
下面我们就来看看,如何使用Canvas做一些我们经常要用到的效果:
1、修改图片的透明度
2、图层的叠加效果(遮罩层)
3、画布的保存和恢复操作
4、使用矩阵实现平移,旋转,缩放动画
5、通过旋转,平移,缩放画布来实现动画
6、裁剪画布
总共六个知识点,讲完这些知识点,现在市面上的View大部分都可以知道原理,以及自己可以动手去绘制了,后面会再写一篇关于自定义ViewGroup系列(LinearLayout,RelativeLayout等)的相关文章。
三、具体实现
我们下面就用例子一一介绍这上面的六个功能点,首先我们先回顾一下,如何自定义一个View,其实很简单,我们只需要集成View类,然后在onDraw方法中,得到一个画布Canvas对象,然后就可以绘制各种我们想要的效果了。
public void onDraw(Canvas canvas)
下面我们先来看看第一个知识点:
1、修改图片的透明度
/** * 修改图片的argb值 * @param sourceImg * @param number * @return */ public static Bitmap getTransparentBitmap(Bitmap sourceImg, int number){ int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()]; sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0, sourceImg .getWidth(), sourceImg.getHeight());// 获得图片的ARGB值 number = number * 255 / 100; for (int i = 0; i < argb.length; i++) { argb[i] = (number << 24) | (argb[i] & 0x00FFFFFF); } sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(), sourceImg .getHeight(), Bitmap.Config.ARGB_8888); return sourceImg; }
我们在onDraw方法绘制出修改之后的图片:
BitmapDrawable drawable = (BitmapDrawable)ctx.getResources().getDrawable(R.drawable.cm_whatsapp_ico_audio); Bitmap bitmap = drawable.getBitmap(); //修改图片的argb值的使用 bitmap = getTransparentBitmap(bitmap, 10); canvas.drawBitmap(bitmap, 0, 0, paint);代码其实很简单,就是拿到原图Bitmap,然后在从新构造一张图片,只是这时候我们会看到这里的技术点:
首先我们可以获取到一张图片的ARGB数组值,数组大小就是图片的像素值,那么每个像素都是一个int类型值:
A代表透明度:8位
RGB代表三基色的颜色值:各8位
那么加起来是32位,正好一个int类型长度。
这个也是在构造图片的时候我们可以看到Bitmap.Config.ARGB_8888的含义,当然这个Config还有其他值,比如:
Bitmap.Config.ALPHA_8:只有透明度的值,8位,那么我们可以使用byte类型就可以了。这张图我们可以想象没有颜色的图片。
Bitmap.Config.ARGB_4444:和ARGB.8888类似,就是占用的位数不一样,这里是4*4=16位,用short类型即可,由此可见ARGB.8888虽然能够显示更高清的图片,但是占用内存会高点。
Bitmap.Config.RGB_565:只有颜色值,没有透明度,占用位数:5+6+5=16位,用short类型即可。
就是在构造一张Bitmap的时候,可以传递新的argb值了,那么意味着我们可以随意的改变图片的透明度,颜色值啥的,我们看一下效果:
下面我们在随便改一下他的颜色值:
for (int i = 0; i < argb.length; i++) { argb[i] = (number << 24) | (argb[i] & 0x00FFFFFF); argb[i] = 400 + (argb[i] & 0xFF00FFFF); }
看一下效果:
知识点:
1>、我们可以使用Bitmap的getPixel方法获取图片的像素值
2>、了解到了图片像素值的表示含义和各个配置之间的差异
3>、修改图片的透明度和颜色值
2、图层的叠加效果(遮罩层)
这个知识点我们可能在前面已经介绍过了,比如如何制作圆角图片,就是用遮罩层来做的,其实遮罩层说白了,就是两张图片之间如何进行叠加,类似于ppt中我们制作图片的时候,可以选择至于上层,至于底层等效果。但是这里的遮罩层的效果会更多,下面来看一下代码实现:
//获得圆角图片的方法 /** * android.graphics.PorterDuff.Mode.SRC:只绘制源图像 android.graphics.PorterDuff.Mode.DST:只绘制目标图像 android.graphics.PorterDuff.Mode.DST_OVER:在源图像的顶部绘制目标图像 android.graphics.PorterDuff.Mode.DST_IN:只在源图像和目标图像相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_OUT:只在源图像和目标图像不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_ATOP:在源图像和目标图像相交的地方绘制目标图像,在不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OVER:在目标图像的顶部绘制源图像 android.graphics.PorterDuff.Mode.SRC_IN:只在源图像和目标图像相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OUT:只在源图像和目标图像不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_ATOP:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.XOR:在源图像和目标图像重叠之外的任何地方绘制他们,而在不重叠的地方不绘制任何内容 android.graphics.PorterDuff.Mode.LIGHTEN:获得每个位置上两幅图像中最亮的像素并显示 android.graphics.PorterDuff.Mode.DARKEN:获得每个位置上两幅图像中最暗的像素并显示 android.graphics.PorterDuff.Mode.MULTIPLY:将每个位置的两个像素相乘,除以255,然后使用该值创建一个新的像素进行显示。结果颜色=顶部颜色*底部颜色/255 android.graphics.PorterDuff.Mode.SCREEN:反转每个颜色,执行相同的操作(将他们相乘并除以255),然后再次反转。结果颜色=255-(((255-顶部颜色)*(255-底部颜色))/255) * @param bitmap * @param roundPx * @return */ public static Bitmap getRoundedCornerBitmap(Bitmap bitmap,float roundPx){ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; }这里我们看到,我们首先可以创造一个画布,但是画布不能为空,需要一个打底图,我们直接使用配置Bitmap.Config.ARGB_8888配置创造一个和原图一样大小的白色图片,当然我们通过上面说的方法,可以创造一个有透明度和颜色值的图片,然后贴在画布上。这里我们看到也可以直接使用画布来设置ARGB的值,这里全是0,这时候我们可以作画了,我们绘制一个圆角矩形,绘制完成之后,我们需要设置画笔的遮罩层效果,这里是关键点,关于遮罩层有很多种选项:
android.graphics.PorterDuff.Mode.SRC:只绘制源图像 android.graphics.PorterDuff.Mode.DST:只绘制目标图像 android.graphics.PorterDuff.Mode.DST_OVER:在源图像的顶部绘制目标图像 android.graphics.PorterDuff.Mode.DST_IN:只在源图像和目标图像相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_OUT:只在源图像和目标图像不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_ATOP:在源图像和目标图像相交的地方绘制目标图像,在不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OVER:在目标图像的顶部绘制源图像 android.graphics.PorterDuff.Mode.SRC_IN:只在源图像和目标图像相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OUT:只在源图像和目标图像不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_ATOP:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.XOR:在源图像和目标图像重叠之外的任何地方绘制他们,而在