欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Android 活动结果 API (II):拍摄和选择照片

最编程 2024-05-24 14:15:07
...

在之前的文章中介绍过如何使用Activity Result API替换onActivityResult方法以及如何进行权限申请。本篇文章介绍下如何使用Activity Result API 实现拍照以及选择手机中的图片。

实现拍照

在之前的文章中提到过,ActivityResutlContract已经有一些官方实现好的默认合约,其中就包含了两个拍照相关的合约TakePictureTakePicturePreview,二者都可以实现拍照功能。

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
    }
}

效果图:

TakePicture_.gif

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)
        }
    }
}

效果图:

TakePicturePreview_.gif

实现选择图片

ActivityResutlContract官方实现好的默认合约中,GetContentGetMultipleContents可以用来获取手机中的资源,因此可以使用这两个合约来获取手机中的图片。

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/*")
        }
    }
}

效果图:

GetContent_.gif

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/*")
        }
    }
}

效果图:

1649486279509549_.gif