先看下结果:
1 private val IMAGE_WIDTH = 200f.toPx 2 private val IMAGE_MARGIN = 20f.toPx 3 class PhotoView(context: Context, attributeSet: AttributeSet): View(context, attributeSet) { 4 5 private val paint = Paint(Paint.ANTI_ALIAS_FLAG) 6 7 private val xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) 8 9 private val bonds = RectF(IMAGE_MARGIN,IMAGE_MARGIN, 10 IMAGE_MARGIN+ IMAGE_WIDTH, IMAGE_MARGIN+ IMAGE_WIDTH) 11 override fun onDraw(canvas: Canvas) { 12 13 //因为下面是一个完全填充的白色的底板 所以看不出效果 14 //所以我们要用到离屏缓冲 15 //离屏缓冲的其中一个作用是帮我们抽出一块区域(透明背景) 16 //我们在离屏缓冲区去画,画完再贴回去 17 //需要提供离屏缓冲的区域,因为离屏缓冲比较消耗资源,所以应该尽可能小 18 val state = canvas.saveLayer(bonds, null) 19 20 //这是画椭圆的方法, 之所以用这个方法画圆,是因为该方法可以传入矩形作为参数 21 //这样就方便我们让圆和矩形重合 22 canvas.drawOval(IMAGE_MARGIN, IMAGE_MARGIN, 23 IMAGE_MARGIN+ IMAGE_WIDTH, IMAGE_MARGIN+ IMAGE_WIDTH, 24 paint) 25 26 paint.xfermode = xfermode 27 canvas.drawBitmap(getBitMap(IMAGE_WIDTH.toInt()), 28 IMAGE_MARGIN, 29 IMAGE_MARGIN, 30 paint) 31 paint.xfermode = null 32 //把离屏缓冲放回去, state:要恢复到之前的第几个状态 33 canvas.restoreToCount(state) 34 } 35 36 //这里对取bitmap做了优化 37 //因为实际的图片像素可能很大,比如,1000, 10000, 像素越大,读取就越慢,越占内存 38 //但是我们需要的图片size是固定的,比如400 39 //options会帮助我们根据需要来读取图片 40 private fun getBitMap(width: Int): Bitmap{ 41 //获取options对象 42 val options = BitmapFactory.Options() 43 //如果设置为true,decoder将返回null(没有bitmap),但out…字段仍将被设置,允许调用者查询bitmap而不必为其像素分配内存。 44 options.inJustDecodeBounds = true 45 //Synonym for opening the given resource and calling decodeResourceStream. 46 //相当于打开资源然后call decode, 但是该方法不一定返回Bitmap, 根据options的配置,它可能返回Null或只返回bitmap的size 47 //这一次只读size 48 BitmapFactory.decodeResource(resources,R.drawable.dogs, options) 49 options.inJustDecodeBounds = false 50 51 //options.outWidth: 位图的结果宽度。如果justdecodebounds设置为false,这将是应用任何缩放后的输出位图的宽度。如果为真,它将是输入图像的宽度,而不考虑任何缩放。 52 //这个图片原来是多大 53 options.inDensity = options.outWidth 54 //我们需要的图片是多大 55 options.inTargetDensity = width 56 return BitmapFactory.decodeResource(resources, R.drawable.dogs, options) 57 } 58 }