Android强制竖屏拍照功能实现遇阻,求助适配不同平板摄像头布局
解决Android强制竖屏拍照并统一照片方向的问题
我来帮你搞定这个困扰!你之前的代码里用MediaStore.EXTRA_SCREEN_ORIENTATION来强制相机竖屏,但这个参数的兼容性极差——大部分第三方相机APP都会直接忽略它,尤其是平板设备因为摄像头位置差异,拍摄出来的照片方向根本没法保证统一。
下面给你一套靠谱的解决方案,核心思路是:不依赖相机APP的方向设置,而是通过读取照片的Exif信息(记录拍摄时的设备方向),手动把照片旋转为竖屏。
步骤1:修正相机启动代码
先去掉不靠谱的EXTRA_SCREEN_ORIENTATION,同时确保我们自己的Activity在拍照前后的方向处理,还要兼容Android 7.0+的FileUri限制:
// 先保存当前Activity的屏幕方向,拍完照后恢复 private int mCurrentOrientation; private File mPhotoFile; // 启动相机的方法 private void launchCamera(int idRow) { // 保存当前方向 mCurrentOrientation = getResources().getConfiguration().orientation; // 临时锁定当前Activity为竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (cameraIntent.resolveActivity(getPackageManager()) != null) { try { // 创建照片存储目录 File storageDir = new File(Environment.getExternalStorageDirectory() + PDF_FOLDER_C); if (!storageDir.exists()) { storageDir.mkdirs(); } // 创建临时照片文件 mPhotoFile = File.createTempFile("capture_photo", ".jpg", storageDir); // Android 7.0+用FileProvider生成安全Uri Uri photoUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", mPhotoFile); cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { photoUri = Uri.fromFile(mPhotoFile); } cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(cameraIntent, idRow); } catch (IOException e) { e.printStackTrace(); // 恢复方向 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } } }
步骤2:添加FileProvider配置(Android 7.0+必需)
在AndroidManifest.xml中注册FileProvider:
<application> <!-- 其他配置 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
然后在res/xml目录下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
步骤3:处理拍照结果,修正照片方向
在onActivityResult中读取照片的Exif方向,然后旋转为竖屏:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 先恢复原来的屏幕方向 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); if (requestCode == idRow && resultCode == RESULT_OK && mPhotoFile != null && mPhotoFile.exists()) { // 1. 获取照片的Exif拍摄方向 int exifOrientation = getExifOrientation(mPhotoFile); // 2. 读取原图并旋转为竖屏 Bitmap originalBitmap = BitmapFactory.decodeFile(mPhotoFile.getAbsolutePath()); Bitmap rotatedBitmap = rotateBitmapToPortrait(originalBitmap, exifOrientation); // 3. 保存旋转后的照片(覆盖原文件) saveRotatedBitmap(rotatedBitmap, mPhotoFile); // 这里可以继续处理照片,比如显示到ImageView // imageView.setImageBitmap(rotatedBitmap); // 回收Bitmap避免内存泄漏 originalBitmap.recycle(); rotatedBitmap.recycle(); } } // 读取照片的Exif方向信息 private int getExifOrientation(File imageFile) { try { ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath()); return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); } catch (IOException e) { e.printStackTrace(); return ExifInterface.ORIENTATION_NORMAL; } } // 根据Exif方向旋转照片为竖屏 private Bitmap rotateBitmapToPortrait(Bitmap bitmap, int exifOrientation) { Matrix matrix = new Matrix(); switch (exifOrientation) { case ExifInterface.ORIENTATION_ROTATE_90: matrix.postRotate(90); break; case ExifInterface.ORIENTATION_ROTATE_180: matrix.postRotate(180); break; case ExifInterface.ORIENTATION_ROTATE_270: matrix.postRotate(270); break; // 其他情况不需要旋转 default: return bitmap; } return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } // 保存旋转后的Bitmap到文件 private void saveRotatedBitmap(Bitmap bitmap, File targetFile) { try { FileOutputStream fos = new FileOutputStream(targetFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } }
关键说明
- 为什么不用EXTRA_SCREEN_ORIENTATION?
这个参数是系统相机的私有约定,第三方相机APP完全可以不遵守,所以靠它强制方向根本不可靠。 - Exif信息的作用?
不管设备摄像头在顶部还是侧面,相机拍摄时都会把设备的旋转角度记录到Exif中,我们只需要根据这个角度修正照片,就能保证最终输出都是竖屏。 - 权限注意事项
别忘了在Manifest中添加权限,Android 6.0+还要动态申请:<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
内容的提问来源于stack exchange,提问作者Mattia




