开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
二、调用摄像头和相册
1.用到的方法
| Uri.fromFile() | 将File对象转换成Uri对象,参数为File对象 |
|---|---|
| FileProvider.getUriForFile() | 将File对象转换成一个封装过的Uri对象,第一个参数是 Context 对象,第二个参数是任意唯一的字符串,第三个参数是File对象。 |
| BitmapFactory.decodeStream() | 将输入流传入,把图片加载成Bitmap |
| imageView.setImageBitmap(): | 显示图片 |
| File(pathname:String) | 通过路径名创建一个新的File实例 |
|---|---|
| File(parent:File,child:String) | 从父抽象路径和子路径名字符串创建新的File实例 |
| File(parent:String,child:String) | 从父路径名字符串和子路径名字符串创建新的File实例 |
| exists() | 路径是否存在 |
| delete() | 删除文件或者路径 |
| createNewFile() | 创建新文件 |
| getPath() | 得到File的路径 |
2.步骤
(1)在布局文件中,添加Button和ImageView
<Button
android:id="@+id/takePhotoBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="take Photo"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
(2)设置变量
private val takePhoto=1
lateinit var imageUri: Uri
lateinit var outputImage:File
(3)创建File对象
将图片命名为output_image.jpg并存放在手机SD卡的应用关联缓存目录下
outputImage = File(externalCacheDir, "output_image.jpg")
if (outputImage.exists()) {//如果路径存在,就先删除
outputImage.delete()
}
outputImage.createNewFile()//创建一个新的File
(4)把File转换成Uri
从Android7.0系统开始,直接使用本地路径的Uri被认为是不安全,会抛出一个FileUriExposedException异常,而FileProvide则是一种特殊的ContentProvider,它使用了和ContentProvider类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。
imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(this, "com.example.cameraman's.fileprovider", outputImage);
} else {
Uri.fromFile(outputImage);
}
(5)启动相机程序
// 启动相机程序
val intent = Intent("android.media.action.IMAGE_CAPTURE")
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
startActivityForResult(intent, takePhoto)
(6)在onActivityResult()函数中,在相机程序拍到的图片显示出来
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val imageView: ImageView = findViewById(R.id.imageView)
when (requestCode) {
takePhoto -> {
if (resultCode == RESULT_OK) {
// 将拍摄的照片显示出来
val bitmap =
BitmapFactory.decodeStream(contentResolver.openInputStream(imageUri))
imageView.setImageBitmap(rotateIfRequired(bitmap))
}
}
}
}
(7)解决调用相机程序去拍照有可能会在一些手机上发生照片旋转的情况
private fun rotateIfRequired(bitmap: Bitmap): Bitmap {
val exif = ExifInterface(outputImage.path)
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
return when (orientation) {
ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmap(bitmap, 90)
ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmap(bitmap, 180)
ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmap(bitmap, 270)
else -> bitmap
}
}
private fun rotateBitmap(bitmap: Bitmap, degree: Int): Bitmap {
val matrix = Matrix()
matrix.postRotate(degree.toFloat())
val rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bitmap.recycle()
return rotatedBitmap
}
(8)在AndroidManifeest.xml对ContentProvider进行注册
android:authorities属性的值必须和刚才FileProvider.getUriForFile()方法中的第二个参数一致,另外,这里还在标签的内部使用指定Uri的共享路径,并引入一个@xml/file_paths资源。
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cameraman's.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
(9)右击res目录->New->Directory,创建一个xml目录,接着右击xml目录->New->File,创建一个file_paths.xml文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="/" />
</paths>