截至 2021 年,这里是完整的答案,您只需复制过去的代码,它应该可以正常工作,它还使用所有新 API,包括权限启动器和 android q 保存图像的方式
我将再添加一项功能,即像这样保存在图片文件夹中的文件夹内
/Pictures/MyAppName/photos.png
此代码还支持 android
我正在截屏并将其保存到桌面以获取图像的 uri,以便以后分享。
首先,android上需要权限启动器
val requestStoragePermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
var saveImageFlag = true
permissions.entries.forEach {
saveImageFlag = it.value
}
if (saveImageFlag) {
shareScreenShootResult()
} else {
showMessage(getString(R.string.cant_share_ScreenShoot))
}
}
val permissionListener: () -> Boolean = {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
true
} else {
requestStoragePermissionLauncher.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
)
false
}
}
然后next方法给出图片名称并设置目录然后分享图片
private fun shareScreenShootResult() {
val dateFormatter by lazy {
SimpleDateFormat(
"yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault()
)
}
val filename = "${getString(R.string.my_ScreenShoot)}${dateFormatter.format(Date())}.png"
val ScreenShootFolderPath = File.separator + requireContext().getAppName()
val uri = binding.rootLayout.makeScreenShot()
.saveScreenShot(requireContext(), filename, ScreenShootFolderPath, permissionListener)
?: return
dispatchShareImageIntent(uri)
}
private fun dispatchShareImageIntent(screenShotUri: Uri) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "image/png"
intent.putExtra(Intent.EXTRA_STREAM, screenShotUri)
startActivity(Intent.createChooser(intent, "Share"))
}
getAppName 是一个扩展函数,你可以将它添加到项目中的任何位置,然后在上下文中调用它,不要忘记导入它。
fun Context.getAppName(): String {
var appName: String = ""
val applicationInfo = applicationInfo
val stringId = applicationInfo.labelRes
appName = if (stringId == 0) {
applicationInfo.nonLocalizedLabel.toString()
} else {
getString(stringId)
}
return appName
}
这个方法makeScreenShot是视图上的扩展函数
您最好将所有扩展功能添加到不同的文件中。
fun View.makeScreenShot(): Bitmap {
setBackgroundColor(Color.WHITE)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
draw(canvas)
return bitmap
}
它返回我正在调用saveScreenShot 的位图,这是另一个扩展函数
fun Bitmap.saveScreenShot(
requireContext: Context,
filename: String,
ScreenShootFolderPath: String,
permissionListener: () -> Boolean,
): Uri? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
saveImageInQ(this, filename, ScreenShootFolderPath, requireContext.contentResolver)
else
legacySave(this, filename, ScreenShootFolderPath, permissionListener)
}
private fun saveImageInQ(
bitmap: Bitmap,
filename: String,
parentFileName: String,
contentResolver: ContentResolver
): Uri? {
val fos: OutputStream?
val uri: Uri?
val contentValues = ContentValues()
contentValues.apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.Files.FileColumns.MIME_TYPE, "image/png")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + parentFileName)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
uri =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
uri?.let { contentResolver.openOutputStream(it) }.also { fos = it }
fos?.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
fos?.flush()
fos?.close()
contentValues.clear()
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
uri?.let {
contentResolver.update(it, contentValues, null, null)
}
return uri
}
private fun legacySave(
bitmap: Bitmap,
filename: String,
parentFileName: String,
permissionListener: () -> Boolean,
): Uri? {
val fos: OutputStream?
if (!permissionListener()) {
return null
}
val path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() +
parentFileName + File.separator + filename
val imageFile = File(path)
if (imageFile.parentFile?.exists() == false) {
imageFile.parentFile?.mkdir()
}
imageFile.createNewFile()
fos = FileOutputStream(imageFile)
val uri: Uri = Uri.fromFile(imageFile)
fos.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
fos.flush()
fos.close()
return uri
}