Android 活动结果 API (II):拍摄和选择照片
最编程
2024-05-24 14:15:07
...
在之前的文章中介绍过如何使用Activity Result API
替换onActivityResult
方法以及如何进行权限申请。本篇文章介绍下如何使用Activity Result API
实现拍照以及选择手机中的图片。
实现拍照
在之前的文章中提到过,ActivityResutlContract
已经有一些官方实现好的默认合约,其中就包含了两个拍照相关的合约TakePicture和TakePicturePreview,二者都可以实现拍照功能。
TakePicture
TakePicture
合约需要传入保存照片文件的Uri,因此需要使用FileProvider
,通过TakePicture
合约实现拍照代码如下:
//在res文件夹下新建xml资源文件夹,并新建file_path.xml资源文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="images"
path="." />
<cache-path
name="cache-path"
path="." />
<external-path
name="external_storage_root"
path="." />
<external-cache-path
name="external_cache_path"
path="." />
</paths>
//在Manifest中配置FileProvider
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
</application>
</manifest>
class PhotoActivity : AppCompatActivity() {
private lateinit var binding: LayoutPhotoActivityBinding
private var photoUri: Uri? = null
private val takePicture =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) {
photoUri?.let {
binding.ivPhoto.setImageURI(it)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)
photoUri = getPhotoFileUri()
binding.btnTakePhoto.setOnClickListener {
takePicture.launch(photoUri)
}
}
//获取保存照片的Uri
private fun getPhotoFileUri(): Uri? {
val storageFile: File? =
if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
externalCacheDir
} else {
cacheDir
}
val photoFile = File.createTempFile("tmp_image_file", ".png", storageFile).apply {
createNewFile()
deleteOnExit()
}
val fileProviderUri = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", photoFile)
return fileProviderUri
}
}
效果图:
TakePicturePreview
通过TakePicturePreview
合约实现拍照代码如下:
class PhotoActivity : AppCompatActivity() {
private lateinit var binding: LayoutPhotoActivityBinding
private val takePicturePreview =
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { photoPreview ->
//该合约返回的是Bitmap,如需保存要进行额外的处理
binding.ivPhoto.setImageBitmap(photoPreview)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)
binding.btnTakePhotoPreview.setOnClickListener {
takePicturePreview.launch(null)
}
}
}
效果图:
实现选择图片
ActivityResutlContract
官方实现好的默认合约中,GetContent和GetMultipleContents可以用来获取手机中的资源,因此可以使用这两个合约来获取手机中的图片。
GetContent
通过GetContent
合约实现选择单张照片代码如下:
class PhotoActivity : AppCompatActivity() {
private lateinit var binding: LayoutPhotoActivityBinding
private val selectPhoto =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
binding.ivPhoto.setImageURI(uri)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)
binding.btnSelectPhoto.setOnClickListener {
//传入的参数就是你想要选择的资源类型
selectPhoto.launch("image/*")
}
}
}
效果图:
GetMultipleContents
通过GetMultipleContents
合约实现选择多张照片代码如下:
class PhotoActivity : AppCompatActivity() {
private lateinit var binding: LayoutPhotoActivityBinding
private val selectMultiplePhoto =
registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { uriList ->
if (uriList.size > 1) {
binding.ivPhoto.setImageURI(uriList[0])
binding.ivPhoto1.setImageURI(uriList[1])
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)
binding.btnSelectMultiplePhoto.setOnClickListener {
//传入的参数就是你想要选择的资源类型
selectMultiplePhoto.launch("image/*")
}
}
}
效果图: