趁着国庆有时间咱们来聊一聊最经常使用的选取用户图片一系列的功能,go!html
效果展现
效果展现连接android
咱们以前设置拍照保存的文件地址的Uri,都是直接Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路径),可是7.0以后,对用户权限提升了保护,以前那种方式行不通了,因此咱们要作7.0的判断,用FileProvider获取设置保存的文件Uri,而后放到Intent.putExtra(MediaStore.EXTRA_OUTPUT,文件保存的Uri路径)中,代码以下:git
//相机拍照的一个标识,后面用 TAKEPAHTO = 1; // 启动系统相机 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //7.0如下设置保存图片的地址 Uri norTakePhotoSaveAdr; // 判断7.0android系统 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //临时添加一个拍照权限 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // //经过FileProvider获取保存图片file的uri(先建立file,而后获取File的Uri) takePhotoSaveAdr = FileProvider.getUriForFile(MainActivity.this, "com.hxzk.bj.photodemo", new File(Environment.getExternalStorageDirectory(), "savephoto.jpg")); //MediaStore.EXTRA_OUTPUT-此设置须要一个保存视频的路径和文件名的Uri intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoSaveAdr); } else { norTakePhotoSaveAdr = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "savephoto.jpg")); intent.putExtra(MediaStore.EXTRA_OUTPUT, norTakePhotoSaveAdr); } //PHOTO_TAKEPHOTO,相机的一个请求码,返回时要用 startActivityForResult(intent, PHOTO_TAKEPHOTO);
相比较拍照,相册要简单一点,代码中都有注释,直接看:github
//拍照的一个表示 TAKEPAHTO = 0; //调用系统图库,选择图片 //Intent.ACTION_PICK 意思是选择数据,其具体表达有: // Intent intent = new Intent(Intent.ACTION_GET_CONTENT); //intent.setType("image/*"); 获取本地图片 // intent.setType("video/*"); 获取本地视频 //intent.setType("audio/*") 获取本地音乐 // Intent intent = new Intent(Intent.ACTION_PICK); // intent.setType(ContactsContract.Contacts.CONTENT_TYPE); //获取联系人 // startActivityForResult(intent, PICK_CONTACT); //第二种写法 Intent intent = new Intent(Intent.ACTION_PICK, null); //其中External为sdcard下的多媒体文件,Internal为system下的多媒体文件。 //使用INTERNAL_CONTENT_URI只能显示存储在内部的照片 intent.setDataAndType( MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*"); //返回结果和标识 startActivityForResult(intent, PHOTO_PHOTOALBUM);
不管是拍照仍是选取图片,咱们都要在Activity的onActivityResult中去获取返回结果,而后进行下一步操做。这里提一下,咱们在跳转相册或拍照都有一个requestCode,如图:
startActivityForResult(intent, PHOTO_PHOTOALBUM);
这个,咱们全局定义了三个,分别是拍照,相册,裁剪的标识:安全
//三个常量全局标识 //图库 private static final int PHOTO_PHOTOALBUM = 0; //拍照 private static final int PHOTO_TAKEPHOTO = 1; //裁剪 private static final int PHOTO_PHOTOCLIP = 2;
在onActivityResult中就要用来区分了:网络
没啥说的!ide
图片的裁剪咱们主要看一下starPhotoZoom()这个裁剪方法,代码以下:优化
public void startPhotoZoom(Uri uri) { Log.e("uri=====", "" + uri); //com.android.camera.action.CROP,这个action是调用系统自带的图片裁切功能 Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*");//裁剪的图片uri和图片类型 intent.putExtra("crop", "true");//设置容许裁剪,若是不设置,就会跳过裁剪的过程,还能够设置putExtra("crop", "circle") intent.putExtra("aspectX", 1);//裁剪框的 X 方向的比例,须要为整数 intent.putExtra("aspectY", 1);//裁剪框的 Y 方向的比例,须要为整数 intent.putExtra("outputX", 60);//返回数据的时候的X像素大小。 intent.putExtra("outputY", 60);//返回数据的时候的Y像素大小。 //uritempFile为Uri类变量,实例化uritempFile if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (TAKEPAHTO == 1) {//若是是7.0的拍照 //开启临时访问的读和写权限 intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); //针对7.0以上的操做 intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, uri)); uriClipUri = uri; } else {//若是是7.0的相册 //设置裁剪的图片地址Uri uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); } } else { uriClipUri = Uri.parse("file://" + "/" + Environment.getExternalStorageDirectory().getPath() + "/" + "clip.jpg"); } Log.e("uriClipUri=====", "" + uriClipUri); //Android 对Intent中所包含数据的大小是有限制的,通常不能超过 1M,不然会使用缩略图 ,因此咱们要指定输出裁剪的图片路径 intent.putExtra(MediaStore.EXTRA_OUTPUT, uriClipUri); intent.putExtra("return-data", false);//是否将数据保留在Bitmap中返回 intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//输出格式,通常设为Bitmap格式及图片类型 intent.putExtra("noFaceDetection", true);//人脸识别功能 startActivityForResult(intent, PHOTO_PHOTOCLIP);//裁剪完成的标识 }
我直接上方法吧:ui
/** * 图片压缩的方法(只是内存减小,避免oom,图片自己在disk盘体积不变) * 显示的Bitmap占用的内存少一点,仍是须要去设置加载的像素长度和宽度(变成缩略图) */ public void compressPhto(File mFile){ // BitmapFactory这个类就提供了多个解析方法(decodeResource、decodeStream、decodeFile等)用于建立Bitmap。 // 好比若是图片来源于网络,就可使用decodeStream方法; // 若是是sd卡里面的图片,就能够选择decodeFile方法; // 若是是资源文件里面的图片,就可使用decodeResource方法等 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 获取当前图片的边界大小 //BitmapFactory.decodeResource(getResources(), R.drawable.bg, options); BitmapFactory.decodeFile(mFile.getAbsolutePath(),options); int outHeight = options.outHeight; //获取图片自己的高像素 int outWidth = options.outWidth;//获取图片自己的宽的像素 String outMimeType = options.outMimeType; options.inJustDecodeBounds = false; //inSampleSize的做用就是能够把图片的长短缩小inSampleSize倍,所占内存缩小inSampleSize的平方 //对于inSampleSize值的大小有要求,最好是整数且2的倍数 options.inSampleSize = caculateSampleSize(options, 500, 500); //etPath()获得的是构造file的时候的路径。getAbsolutePath()获得的是全路径 String path =mFile.getPath(); String absPath=mFile.getAbsolutePath(); Bitmap bitmap = BitmapFactory.decodeFile(absPath,options); ivUserPhoto.setImageBitmap(bitmap); //尺寸压缩结果 ivSize.setImageBitmap(bitmap); } /** * 计算出所须要压缩的大小 * @param options * @param reqWidth 但愿的图片宽大小 * @param reqHeight 但愿的图片高大小 * @return */ private int caculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int sampleSize = 1; int picWidth = options.outWidth; int picHeight = options.outHeight; if (picWidth > reqWidth || picHeight > reqHeight) { int halfPicWidth = picWidth / 2; int halfPicHeight = picHeight / 2; while (halfPicWidth / sampleSize > reqWidth || halfPicHeight / sampleSize > reqHeight) { sampleSize *= 2; } } return sampleSize; }
不知道,你们注意裁剪方法里的这一段代码没?this
还有拍照的这一段代码:
为何要这么写呢?
原来7.0一下版本咱们,直接调用相机获取的图片地址是:
file:///storage/emulated/0/temp.jpg的文件
然而7.0以后就变成:
content://........文件,使用 content://代替了 file:///
这是由于:Android 为了提升私有文件的安全性,从 7.0 开始对外传递file://类型的uri会触发FileUriExposedException。所以,在分享私有文件时必须使用FileProvider。
那么若是在使用以前的方法就会报错,咱们要给程序在manifest文件中加入FileProvider:
咱们看看provider_paths这个文件中都有啥?
这注解写的,不会,就转行吧。
直接加载图片显示
上传图片
但还有中状况是咱们要上传加载的图片,我也给你们提供了方法:
Bitmap photoBitmap; File file; /** * 上传图片 */ public void upDateFile() { try { //裁剪后的图像转成BitMap photoBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uriClipUri)); } catch (FileNotFoundException e) { e.printStackTrace(); } //建立路径 String path = Environment.getExternalStorageDirectory() .getPath() + "/Pic"; //获取外部储存目录 file = new File(path); //建立新目录, 建立此抽象路径名指定的目录,包括建立必需但不存在的父目录。 file.mkdirs(); //以当前时间从新命名文件 long time = System.currentTimeMillis(); //生成新的文件 file = new File(file.toString() + "/" + time+ ".png"); //建立输出流 OutputStream out = null; try { out = new FileOutputStream(file.getPath()); } catch (FileNotFoundException e) { e.printStackTrace(); } //压缩文件,返回结果,true说明成功了 boolean bCompress = photoBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); }
暂时这么多,之后补充!
Github地址
做者:薛之涛 连接:https://www.jianshu.com/p/832d723039da 來源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。