赞
踩
前段时间写了如何获取相册和拍照之后的照片并且进行显示和上传,这一次是如何进行圆形图像制作,经常看我写的笔记的人会知道,我很懒。那么我就懒的自定义了,目前需求就用原生的就好了,大神的轮子,我会在后面进行推荐。这篇笔记是依赖于:Android调用相册、相机(兼容6.0、7.0、8.0)
文章撰写的,所以不会基本操作的,请先去看看那个。
先上效果哈:
##一、布局设置
由于是圆形头像,所以,我们引用一个举世闻名的项目哈:CircleImageView
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout 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"
- tools:context=".MainActivity">
-
- <Button
- android:id="@+id/btn_get_pic_form_photo_album"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_margin="10dp"
- android:text="调用相册" />
-
- <Button
- android:id="@+id/btn_get_Permission"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_margin="10dp"
- android:text="动态权限申请" />
-
- <Button
- android:id="@+id/btn_get_pic_from_camera"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:layout_margin="10dp"
- android:text="调用相机" />
-
- <de.hdodenhof.circleimageview.CircleImageView
- android:id="@+id/iv_test"
- android:layout_width="96dp"
- android:layout_height="96dp"
- android:layout_centerInParent="true"
- android:src="@drawable/ic_launcher_background"
- app:civ_border_color="#999999"
- app:civ_border_width="2dp" />
- </RelativeLayout>
布局没有太大变化,就是把之前的ImageView
修改为CircleImageView
控件
##二、.java 文件
这里增加了两个方法
######方法一
- private void photoClip(Uri uri) {
- // 调用系统中自带的图片剪裁
- Intent intent = new Intent("com.android.camera.action.CROP");
- intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- intent.setDataAndType(uri, "image/*");
- // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
- intent.putExtra("crop", "true");
- // aspectX aspectY 是宽高的比例
- intent.putExtra("aspectX", 1);
- intent.putExtra("aspectY", 1);
- // outputX outputY 是裁剪图片宽高
- intent.putExtra("outputX", 150);
- intent.putExtra("outputY", 150);
- intent.putExtra("return-data", true);
- startActivityForResult(intent, 3);
- }
该方法,传入我们拿到的照片的 uri 进行激活 Android 系统的裁剪界面。我是在 onActivityResult 内进行调用该方法。
######方法二
- public String saveImage(String name, Bitmap bmp) {
- File appDir = new File(Environment.getExternalStorageDirectory().getPath());
- if (!appDir.exists()) {
- appDir.mkdir();
- }
- String fileName = name + ".jpg";
- File file = new File(appDir, fileName);
- try {
- FileOutputStream fos = new FileOutputStream(file);
- bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
- fos.flush();
- fos.close();
- return file.getAbsolutePath();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
该方法 传入获取照片的 bitmap 和裁剪之后的照片名称,生成文件的保存路径,韩小呆将其保存在了本地的根目录了。
完整代码
- package com.example.hxd.pictest;
-
- import android.Manifest;
- import android.content.Intent;
- import android.graphics.Bitmap;
- import android.net.Uri;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.SystemClock;
- import android.provider.MediaStore;
- import android.support.annotation.NonNull;
- import android.support.v4.content.FileProvider;
- import android.support.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.Toast;
-
- import com.bumptech.glide.Glide;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.List;
- import java.util.Objects;
- import java.util.logging.Logger;
-
- import de.hdodenhof.circleimageview.CircleImageView;
- import pub.devrel.easypermissions.EasyPermissions;
-
- public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {
-
- private CircleImageView ivTest;
-
- private File cameraSavePath;//拍照照片路径
- private Uri uri;
- private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
-
- private String photoName = System.currentTimeMillis() + ".jpg";
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button btnGetPicFromCamera = findViewById(R.id.btn_get_pic_from_camera);
- Button btnGetPicFromPhotoAlbum = findViewById(R.id.btn_get_pic_form_photo_album);
- Button btnGetPermission = findViewById(R.id.btn_get_Permission);
- ivTest = findViewById(R.id.iv_test);
-
- btnGetPicFromCamera.setOnClickListener(this);
- btnGetPicFromPhotoAlbum.setOnClickListener(this);
- btnGetPermission.setOnClickListener(this);
-
- cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + photoName);
-
- }
-
- @Override
- public void onClick(View v) {
- int id = v.getId();
- switch (id) {
- case R.id.btn_get_pic_from_camera:
- goCamera();
- break;
- case R.id.btn_get_pic_form_photo_album:
- goPhotoAlbum();
- break;
- case R.id.btn_get_Permission:
- getPermission();
- break;
- }
- }
-
- //获取权限
- private void getPermission() {
- if (EasyPermissions.hasPermissions(this, permissions)) {
- //已经打开权限
- Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show();
- } else {
- //没有打开相关权限、申请权限
- EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions);
- }
-
- }
-
-
- private void photoClip(Uri uri) {
- // 调用系统中自带的图片剪裁
- Intent intent = new Intent("com.android.camera.action.CROP");
- intent.setDataAndType(uri, "image/*");
- // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
- intent.putExtra("crop", "true");
- // aspectX aspectY 是宽高的比例
- intent.putExtra("aspectX", 1);
- intent.putExtra("aspectY", 1);
- // outputX outputY 是裁剪图片宽高
- intent.putExtra("outputX", 150);
- intent.putExtra("outputY", 150);
- intent.putExtra("return-data", true);
- startActivityForResult(intent, 3);
-
-
- }
-
-
- //激活相册操作
- private void goPhotoAlbum() {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_PICK);
- intent.setType("image/*");
- startActivityForResult(intent, 2);
- }
-
- //激活相机操作
- private void goCamera() {
- Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- } else {
- uri = Uri.fromFile(cameraSavePath);
- }
- intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
- MainActivity.this.startActivityForResult(intent, 1);
- }
-
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- //框架要求必须这么写
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
- }
-
-
- //成功打开权限
- @Override
- public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
-
- Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show();
- }
-
- //用户未同意权限
- @Override
- public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
- Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show();
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- String photoPath;
- if (requestCode == 1 && resultCode == RESULT_OK) {
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- photoPath = String.valueOf(cameraSavePath);
- photoClip(Uri.fromFile(cameraSavePath));
- } else {
- photoPath = uri.getEncodedPath();
- photoClip(uri);
- }
- Log.d("拍照返回图片路径:", photoPath);
- Glide.with(MainActivity.this).load(photoPath).into(ivTest);
- } else if (requestCode == 2 && resultCode == RESULT_OK) {
- photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
- Log.d("相册返回图片路径:", photoPath);
- photoClip(data.getData());
- Glide.with(MainActivity.this).load(photoPath).into(ivTest);
- } else if (requestCode == 3 && resultCode == RESULT_OK) {
- Bundle bundle = data.getExtras();
-
- if (bundle != null) {
- //在这里获得了剪裁后的Bitmap对象,可以用于上传
- Bitmap image = bundle.getParcelable("data");
- //设置到ImageView上
- ivTest.setImageBitmap(image);
- //也可以进行一些保存、压缩等操作后上传
- String path = saveImage("头像", image);
- Log.d("裁剪路径:", path);
- }
-
-
- }
-
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- public String saveImage(String name, Bitmap bmp) {
- File appDir = new File(Environment.getExternalStorageDirectory().getPath());
- if (!appDir.exists()) {
- appDir.mkdir();
- }
- String fileName = name + ".jpg";
- File file = new File(appDir, fileName);
- try {
- FileOutputStream fos = new FileOutputStream(file);
- bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
- fos.flush();
- fos.close();
- return file.getAbsolutePath();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- }
当代码写成了这样,我以为就可以完事了,但是后来拿出来我的小米4和小米8se 测试的时候,我就懵逼了,出现了如下结果:
描述一下:
1、相册选择照片之后,只要进行裁剪就会出现“保存时发生错误,保存失败”;
2、就是拍照之后进行裁剪无效果。
#三、解决bug
###1、将 photoClip() 方法内添加如下代码,其他代码不进行变动
- uritempFile = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");
- intent.putExtra(MediaStore.EXTRA_OUTPUT, uritempFile);
- intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
- intent.putExtra("noFaceDetection", true);
这里的 uritempFile
是个 Uri 。
###2、将裁剪的返回成功的返回方法内添加如下代码:
- Picasso.with(EditMyInfoActivity.this).load(uritempFile).into(ivHead);
- File file = null;
- try {
- file = new File(new URI(uritempFile.toString()));
- } catch (URISyntaxException e) {
- e.printStackTrace();
- }
- //照片路径
- String path = Objects.requireNonNull(file).getPath();
然后,就可以完美的运行了。
##三、推荐一篇自定义裁剪的博文
Android 高仿微信头像截取 打造不一样的自定义控件----作者: 家喻户晓的 张鸿洋
##四、推荐几款裁剪框架
1、uCrop—薄荷,哔哩哔哩 在使用
2、android-crop—网易新闻,芒果TV 在使用
3、PhotoCrop—快手 使用
4、CropBitmap—>出自一位牛x的群友
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。