Android 实现拍照 和拉起相册库(带裁剪照片功能)
程序员文章站
2022-07-04 09:22:53
布局文件:
布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/iv" android:layout_width="200dp" android:layout_height="200dp" /> <Button android:id="@+id/btn_takephoto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="拍照" /> <Button android:id="@+id/btn_open_photo_album" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="相册库" /> </LinearLayout>
MainActivity
private static final String TAG = "MainActivity"; private static final int REQUEST_TAKE_PHOTO = 0;// 拍照 private static final int REQUEST_CROP = 1;// 裁剪 private static final int SCAN_OPEN_PHONE = 2;// 相册 private static final int REQUEST_PERMISSION = 100; private ImageView img; private Uri imgUri; // 拍照时返回的uri private Uri mCutUri;// 图片裁剪时返回的uri private File imgFile;// 拍照保存的图片文件 private boolean hasPermission = false;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.btn_takephoto).setOnClickListener(this); findViewById(R.id.btn_open_photo_album).setOnClickListener(this); img = findViewById(R.id.iv); checkPermissions(); }
private void checkPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 检查是否有存储和拍照权限 if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED ) { hasPermission = true; } else { requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, REQUEST_PERMISSION); } } }
@Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_takephoto: if (hasPermission) { takePhone(); } break; case R.id.btn_open_photo_album: if (hasPermission) { openGallery(); } break; } }
// 拍照 private void takePhone() { // 要保存的文件名 String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date()); String fileName = "photo_" + time; // 创建一个文件夹 String path = Environment.getExternalStorageDirectory() + "/take_photo"; File file = new File(path); if (!file.exists()) { file.mkdirs(); } // 要保存的图片文件 imgFile = new File(file, fileName + ".jpeg"); // 将file转换成uri // 注意7.0及以上与之前获取的uri不一样了,返回的是provider路径 imgUri = getUriForFile(this, imgFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 添加Uri读取权限 intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); // 或者 grantUriPermission("com.rain.takephotodemo", imgUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); // 添加图片保存位置 intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); startActivityForResult(intent, REQUEST_TAKE_PHOTO); }
//相册库 private void openGallery() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, SCAN_OPEN_PHONE); }
// 从file中获取uri // 7.0及以上使用的uri是contentProvider content://com.rain.takephotodemo.FileProvider/images/photo_20180824173621.jpg // 6.0使用的uri为file:///storage/emulated/0/take_photo/photo_20180824171132.jpg private static Uri getUriForFile(Context context, File file) { if (context == null || file == null) { throw new NullPointerException(); } Uri uri; if (Build.VERSION.SDK_INT >= 24) { uri = FileProvider.getUriForFile(context.getApplicationContext(), "com.example.myapplication.FileProvider", file); } else { uri = Uri.fromFile(file); } return uri; }
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { hasPermission = true; } else { Toast.makeText(this, "权限授予失败!", Toast.LENGTH_SHORT).show(); hasPermission = false; } } }
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { // 拍照并进行裁剪 case REQUEST_TAKE_PHOTO: Log.e(TAG, "拍照并进行裁剪:" + imgUri.toString()); cropPhoto(imgUri, true); break; // 裁剪后设置图片 case REQUEST_CROP: img.setImageURI(mCutUri); Log.e(TAG, "裁剪后设置图片:REQUEST_CROP:" + mCutUri.toString()); break; // 打开图库获取图片并进行裁剪 case SCAN_OPEN_PHONE: Log.e(TAG, "打开图库获取图片并进行裁剪:" + data.getData().toString()); cropPhoto(data.getData(), false); break; } } }
// 图片裁剪 private void cropPhoto(Uri uri, boolean fromCapture) { Intent intent = new Intent("com.android.camera.action.CROP"); //打开系统自带的裁剪图片的intent // 注意一定要添加该项权限,否则会提示无法裁剪 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setDataAndType(uri, "image/*"); intent.putExtra("scale", true); // 设置裁剪区域的宽高比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // 设置裁剪区域的宽度和高度 intent.putExtra("outputX", 200); intent.putExtra("outputY", 200); // 取消人脸识别 intent.putExtra("noFaceDetection", true); // 图片输出格式 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); // 若为false则表示不返回数据 intent.putExtra("return-data", false); // 指定裁剪完成以后的图片所保存的位置,pic info显示有延时 if (fromCapture) { // 如果是使用拍照,那么原先的uri和最终目标的uri一致,注意这里的uri必须是Uri.fromFile生成的 mCutUri = Uri.fromFile(imgFile); } else { // 从相册中选择,那么裁剪的图片保存在take_photo中 String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date()); String fileName = "photo_" + time; File mCutFile = new File(Environment.getExternalStorageDirectory() + "/take_photo", fileName + ".jpeg"); if (!mCutFile.getParentFile().exists()) { mCutFile.getParentFile().mkdirs(); } mCutUri = Uri.fromFile(mCutFile); } intent.putExtra(MediaStore.EXTRA_OUTPUT, mCutUri); // Toast.makeText(this, "剪裁图片", Toast.LENGTH_SHORT).show(); // 以广播方式刷新系统相册,以便能够在相册中找到刚刚所拍摄和裁剪的照片 Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intentBc.setData(uri); this.sendBroadcast(intentBc); startActivityForResult(intent, REQUEST_CROP); //设置裁剪参数显示图片至ImageVie }
xml
public_file_path
<?xml version="1.0" encoding="utf-8"?> <resources> <external-path name="images" path="take_photo/"/> </resources>
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.myapplication.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/public_file_path" /> </provider>
权限
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
以上就是全部内容,希望对你开发有所帮助!!
本文地址:https://blog.csdn.net/shuai497331206/article/details/107908502
上一篇: 去吃饭
下一篇: Flutter 获取设备屏幕的宽高