使用PixelCopy截图

5,686 阅读2分钟

业务中遇到了需要局部截图的业务逻辑,百度出来使用缓存的方式截图,但是copy后发现好多删除线,然后官方文档提示已经过时,建议使用PIxelCopy API

For screenshots of the UI for feedback reports or unit testing the PixelCopy API is recommended.

现将我封装的代码复制出来,大家直接用吧!

/**
     * 将View转换成Bitmap
     */
    fun createBitmapFromView(window: Window, view: View, callBack: (Bitmap?, Boolean) -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            var bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888, true)
            convertLayoutToBitmap(
                window, view, bitmap
            ) { copyResult -> //如果成功
                if (copyResult == PixelCopy.SUCCESS) {
                    callBack(bitmap,true)
                }else{
                    callBack(null,false)
                }
            }
        } else {
            var bitmap: Bitmap? = null
            //开启view缓存bitmap
            view.isDrawingCacheEnabled = true
            //设置view缓存Bitmap质量
            view.drawingCacheQuality = View.DRAWING_CACHE_QUALITY_HIGH
            //获取缓存的bitmap
            val cache: Bitmap = view.getDrawingCache()
            if (cache != null && !cache.isRecycled) {
                bitmap = Bitmap.createBitmap(cache)
            }
            //销毁view缓存bitmap
            view.destroyDrawingCache()
            //关闭view缓存bitmap
            view.setDrawingCacheEnabled(false)
            callBack(bitmap,bitmap!=null)
        }

    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun convertLayoutToBitmap(
        window: Window, view: View, dest: Bitmap,
        listener: PixelCopy.OnPixelCopyFinishedListener
    ) {
        //获取layout的位置
        val location = IntArray(2)
        view.getLocationInWindow(location)
        //请求转换
        PixelCopy.request(
            window,
            Rect(location[0], location[1], location[0] + view.width, location[1] + view.height),
            dest, listener, Handler(Looper.getMainLooper())
        )
    }

保存图片一起复制出来吧!

fun saveBitmapGallery(context: Context, bitmap: Bitmap): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //返回出一个URI
            val insert = context.contentResolver.insert(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                /*
                这里如果不写的话 默认是保存在 /sdCard/DCIM/Pictures
                 */
                ContentValues()//这里可以啥也不设置 保存图片默认就好了
            ) ?: return false //为空的话 直接失败返回了

            //这个打开了输出流  直接保存图片就好了
            context.contentResolver.openOutputStream(insert).use {
                it ?: return false
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
            }
            return true
        } else {
            MediaStore.Images.Media.insertImage(context.contentResolver, bitmap, "title", "desc")
            return true
        }
    }

    fun saveFile2Gallery(context: Context, url: String): Boolean {
        //返回出一个URI
        val insert = context.contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            /*
            这里可以默认不写 默认保存在
             */
            ContentValues()
        ) ?: return false //为空的话 直接失败返回了
        //这个打开了输出流  直接保存图片就好了
        context.contentResolver.openOutputStream(insert).use { os ->
            os ?: return false
            var x = download(url, os)
            return x
        }
        return false
    }


    private fun download(url: String, os: OutputStream): Boolean {
        val url = URL(url)
        (url.openConnection() as HttpURLConnection).also { conn ->
            conn.requestMethod = "GET"
            conn.connectTimeout = 5 * 1000
            if (conn.responseCode == 200) {
                conn.inputStream.use { ins ->
                    val buf = ByteArray(2048)
                    var len: Int
                    while (ins.read(buf).also { len = it } != -1) {
                        os.write(buf, 0, len)
                    }
                    os.flush()
                }
                return true
            } else {
                return false
            }
        }
    }

使用

下面用到了kotlin1.4的特性 SAM转换,不知道低版本支不支持,应该可以用普通的lambda传参

PhotoUtils.createBitmapFromView(window, binding.cvShare) {bitmap,isCopySuccess-> 
                   if(isCopySuccess){                        
                        bitmap?.let {
                            PhotoUtils.saveBitmapGallery(this, bitmap)
                            showPromptMessage("保存成功")
                        }
                    }else{
                        showPromptMessage("保存失败")
                    }
                }