**

开篇:

**
1.讲解Intent中的四个重要属性——Action、Data、Category、Extras
2.关于 Android 7.0 适配中 FileProvider 部分的总结
3.Environment.getExternalStorageState介绍
4.思路:
/*
*整理具体思路
* .获取权限
* .选择是拍照还是相册
* .返回uri
* .进行裁剪
* .显示头像
* 关键要能理清图片的路径
*/

运行效果:

导入依赖

    //glide 图片加载implementation 'com.github.bumptech.glide:glide:4.8.0'annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'//动态权限申请库implementation 'pub.devrel:easypermissions:1.3.0'

代码部分


package com.ycb.baseicon.utils;import android.os.Environment;import java.io.File;
import java.util.UUID;public class FileStorage {private File cropIconDir;private File iconDir;public FileStorage() {//MEDIA_MOUNTED  SD卡正常使用 TRUE TRUE TRUE TRUE TRUE//只有在SD卡状态为MEDIA_MOUNTED时/mnt/sdcard目录才是可读可写,并且可以创建目录及文件。if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {File external = Environment.getExternalStorageDirectory();//获取sd卡 路径String rootDir = "/" + "Base";cropIconDir = new File(external, rootDir + "/crop");if (!cropIconDir.exists()) { // 检测是否有这个目录存在cropIconDir.mkdirs();   //创建}iconDir = new File(external, rootDir + "/icon");if (!iconDir.exists()) {iconDir.mkdirs();}}}//裁剪存放目录public File createCropFile() {String fileName = "";if (cropIconDir != null) {//UUID  设备唯一标识码fileName = UUID.randomUUID().toString() + ".png";}return new File(cropIconDir, fileName);  // cropIconDir: File对象类型的目录路径    fileName:文件名或目录名。}//头像存放目录public File createIconFile() {String fileName = "";if (iconDir != null) {fileName = UUID.randomUUID().toString() + ".png";}return new File(iconDir, fileName);}}

MainActivity(解释都写好了)

package com.ycb.baseicon;import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.ycb.baseicon.PopupWindow.CommonPopupWindow;
import com.ycb.baseicon.PopupWindow.CommonUtil;
import com.ycb.baseicon.utils.FileStorage;
import com.ycb.baseicon.utils.PictureUtil;
import com.ycb.baseicon.utils.SPUtils;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;import pub.devrel.easypermissions.EasyPermissions;public class MainActivity extends AppCompatActivity implements CommonPopupWindow.ViewInterface, EasyPermissions.PermissionCallbacks {private CommonPopupWindow commonPopupWindow;private ImageView mIcon;private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA};//Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。换句话说:android系统中任何可用的资源(图像、视频、文件)// 都可以用uri表示。//uri讲解://1.uri属性有以下4部分组成:android:scheme、android:host、android:port、android:path//其中host和port2个统称为authority。//2.要使authority(host和port)有意义,必须指定scheme;要使path有意义,必须使scheme和authority(host和port)有意义private Uri uri;private int type;Uri cropUri;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mIcon = findViewById(R.id.icon);String path = SPUtils.getString(this, "icon", "");if (path != null) {loadCircleImage(this, path, mIcon);}mIcon.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {showAll(v);}});}//全屏弹出public void showAll(View view) {if (commonPopupWindow != null && commonPopupWindow.isShowing()) return;View upView = LayoutInflater.from(this).inflate(R.layout.popup_up, null);//测量View的宽高CommonUtil.measureWidthAndHeight(upView);commonPopupWindow = new CommonPopupWindow.Builder(this).setView(R.layout.popup_up).setWidthAndHeight(ViewGroup.LayoutParams.MATCH_PARENT, upView.getMeasuredHeight()).setBackGroundLevel(0.5f)//取值范围0.0f-1.0f 值越小越暗.setAnimationStyle(R.style.AnimUp).setViewOnclickListener(this).create();commonPopupWindow.showAtLocation(findViewById(android.R.id.content), Gravity.BOTTOM, 0, 0);}@Overridepublic void getChildView(View view, int layoutResId) {switch (layoutResId) {case R.layout.popup_up:Button btn_take_photo = (Button) view.findViewById(R.id.btn_take_photo);Button btn_select_photo = (Button) view.findViewById(R.id.btn_select_photo);Button btn_cancel = (Button) view.findViewById(R.id.btn_cancel);btn_take_photo.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {type = 1;                 getPermission();    //写个if  判断是不是在6.0以上版本   不是直接调用方法if (commonPopupWindow != null) {commonPopupWindow.dismiss();}}});btn_select_photo.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {type = 2;getPermission();if (commonPopupWindow != null) {commonPopupWindow.dismiss();}}});btn_cancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (commonPopupWindow != null) {commonPopupWindow.dismiss();}}});view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (commonPopupWindow != null) {commonPopupWindow.dismiss();}return true;}});break;}}//获取权限public void getPermission() {//检测是否有权限if (EasyPermissions.hasPermissions(this, permissions)) {switch (type) {case 1:getCamera();break;case 2:getPhotoAlbum();break;}} else {EasyPermissions.requestPermissions(this, "用于读取相册和拍照功能", 1, permissions);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}//权限申请成功@Overridepublic void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {switch (type) {case 1:getCamera();break;case 2:getPhotoAlbum();break;}}//权限申请失败时的回调@Overridepublic void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {showToast("请在应用管理里面对应用进行重新授权");finish();}/* intent 的重要属性* Action:Action属性的值为一个字符串,它代表了系统中已经定义了一系列常用的动作。* 通过setAction()方法或在清单文件AndroidManifest.xml中设置。默认为:DEFAULT。*Data:Data通常是URI格式定义的操作数据。例如:tel:// 。通过setData()方法设置。*Category:Category属性用于指定当前动作(Action)被执行的环境。通过addCategory()方法或在清单文件AndroidManifest.xml中设置。*默认为:CATEGORY_DEFAULT。*Extras:Extras属性主要用于传递目标组件所需要的额外的数据。通过putExtras()方法设置。*///相册public void getPhotoAlbum() {Intent intent = new Intent();intent.setAction(Intent.ACTION_PICK);intent.setType("image/*");  //type  指定获取 image类型的所有文件startActivityForResult(intent, 2);//系统相册选图返回的Uri是可以直接使用的,不需要也不能使用FileProvider进行转换}//照相功能/*思路* 首先是调用相机  意图* 第二步 获取图片路径* 最后保存并返回*/private void getCamera() {File file = new FileStorage().createCropFile()/*   方法                               描述File(File dir, String name) File对象类型的目录路径,name为文件名或目录名。File(String path)   path为新File对象的路径。File(String dirPath, String name)   dirPath为指定的文件路径,name为文件名或目录名。File(URI uri)   使用URI指定路径来创建新的File对象。*/Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {uri = FileProvider.getUriForFile(this, "com.ycb.baseicon.fileProvider", file);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//临时授予读写权限} else {//低版本路径转成uriuri = Uri.fromFile(file);}intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);  //将图片保存在这个位置startActivityForResult(intent, 1);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {switch (requestCode) {//照相case 1://此处不可写成 data.getData// 因为上面通过putExtra  将地址存在了 uri  这个指定的路径里面startPhotoZoom(uri);break;//相册case 2://从相册返回的uri  可以看在getPhotoAlbum处的注解startPhotoZoom(data.getData());// content                  mediaLog.i("文件地址", data.getScheme() + " " + data.getData().getAuthority() +data.getData().getHost() + data.getData().getPort() + "  " + data.getData().getPath() + "\n" + data.getData());//content://media/external/images/media/1036430   path: /external/images/media/1036430break;//裁剪case 3:Bundle bundle = data.getExtras();if (bundle != null) {//裁剪处有对照表  键名为data   类型是 parcelable   value (因为写的是true )  bitmapBitmap bitmap = bundle.getParcelable("data");String path = saveImage(bitmap);loadCircleImage(this, path, mIcon);SPUtils.putString(this, "icon", path);}Log.i("Uri", cropUri.toString());/*      if (cropUri!=null){Bitmap bitmap ;  当使用false时try {   这种方法提示获取的地址不存在bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(cropUri));loadCircleImage(this,bitmap,mIcon);} catch (FileNotFoundException e) {e.printStackTrace();}}*/break;}super.onActivityResult(requestCode, resultCode, data);}//裁剪方法 private void startPhotoZoom(Uri uri) {File file = new FileStorage().createCropFile();cropUri = Uri.fromFile(file);  //file 类型转成了 uri 类型 最后在下面使用   最终将裁剪后的图片保存在这个指定的位置//调用系统裁剪的意图Intent intent = new Intent("com.android.camera.action.CROP");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//添加这一句表示对目标应用临时授权该Uri所代表的文件intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);}
/*      crop        String     发送裁剪信号aspectX        int        X方向上的比例aspectY       int        Y方向上的比例outputX       int        裁剪区的宽outputY     int        裁剪区的高scale       boolean    是否保留比例return-data    boolean    是否将数据保留在Bitmap中返回data       Parcelable  相应的Bitmap数据circleCrop    String     圆形裁剪区域?MediaStore.EXTRA_OUTPUT ("output")   URI  将URI指向相应的file:///...,详见代码示例outputFormat String  输出格式,一般设为Bitmap格式:Bitmap.CompressFormat.JPEG.toString()noFaceDetection    boolean 是否取消人脸识别功能*/intent.setDataAndType(uri, "image/*");  //设置data (uri) 和type  类型intent.putExtra("crop", "true");intent.putExtra("aspectX", 1); // 裁剪框比例intent.putExtra("aspectY", 1);intent.putExtra("outputX", 300); // 输出图片大小intent.putExtra("outputY", 300);intent.putExtra("scale", true);//Intent 的data域最大传递的值的大小约为1M,所以图片的BITMAP当超过1M时就会失败 : 无法传递大图  false 传递uriintent.putExtra("return-data", true);  //true  表示返回的是bitmap对象  为true的情况下 一般在图片尺寸480*480 崩溃intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);  //将 图像转移保存到  -》 croupUri   :   uri位置intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());intent.putExtra("noFaceDetection", true); // no face detectionstartActivityForResult(intent, 3);}public void showToast(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}/*** 加载圆形图片*/public static void loadCircleImage(Context context, String path, ImageView imageView) {// RequestOptions  扩展glide  自定义加载方式RequestOptions options = new RequestOptions().centerCrop().circleCrop()//设置圆形.diskCacheStrategy(DiskCacheStrategy.ALL);Glide.with(context).load(path).apply(options).into(imageView);}//获取图像的String类型path 地址   可以用于保存或者上传到服务器public String saveImage(Bitmap bmp) {File file = new FileStorage().createIconFile();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;}}

总结

个人认为最终裁剪的图片可以把它的path地址上传到服务器上面,然后在把服务器接口返回的图片地址保存起来,用glide显示

代码下载

安卓个人中心头像模块(从相册选择和照相功能,适配7.0)相关推荐

  1. app头像上传vue_VUE上传头像,从相册选择、调用摄像头,ios适用transPath的转换

    HTML //这个图片是田字格,样式 //这是要上传的图片 //删除的图片 // 这个点击保存,是手机上选择好相片才会出来的 点击保存 立即申请 样式: #confrim{ width: 100%; ...

  2. android之跳转相册选择图片/照相

    使用环境: 跳转相册选择图片的时候,对于不同类型的图片有不同该类型的返回值: 这里说的就是vivo手机跳转相册返回的地址: 1 小米正常返回地址: file:///storage/emulated/0 ...

  3. android从本地相册选择图片uri三星手机适配问题

    转载地址:http://blog.csdn.net/CathyChen0910/article/details/62456438 启动系统相册intent Intent intentFromGalle ...

  4. Android实现相机拍照和相册选择以及图片裁剪适配Android10以上

    之前写的一个工具类,在华为手机Android版本12上无法返回图片路径,提示不是一个文件或是文件不存在. 所以更改此工具类如下: package com.suoer.comeonhealth.laib ...

  5. 仿微信拍照和图片选择开源库(适配android7.0)multi-image-selector

    资源下载地址,使用时以Module的形式导入项目中使用 链接:http://pan.baidu.com/s/1cbySwe 提取码:yl9u 使用准备 /*** 选择的照片*/private List ...

  6. Android的实现既能相册选择,拍照选择,点击每张图片又能放大查看!

    最近很长一段时间没有更新博客了实在是比较忙最近需要使用一个功能:选择本机相册或者拍照返回图片显示到九宫格中,并且可以点击九宫格每一张放大查看,滑动等功能! 在网上也看到一些大神写的演示和第三方库,不过 ...

  7. iOS打开照相机与本地相册选择图片

    最近正好项目里面要集成"打开照相机与本地相册选择图片"的功能,今天就在这边给大家写一个演示程序:打开相机拍摄后或者在相册中选择一张照片,然后将它显示在界面上.好了废话不多说,因为比 ...

  8. iOS 打开照相机与本地相册选择图片

    最近正好项目里面要集成"打开照相机与本地相册选择图片"的功能,今天就在这边给大家写一个演示程序:打开相机拍摄后或者在相册中选择一张照片,然后将它显示在界面上.好了废话不多说,因为比 ...

  9. Android 点击换头像(拍照和从相册选择)

    Android 点击换头像(拍照和从相册选择) 首先是layout里的代码,但这之前需要在build.gradle里加两行代码,主要是圆形图片和别的按钮啥的,你也可以改成自己的,不加圆形图片用系统原来 ...

最新文章

  1. java11 是长期支持_这里有你不得不了解的Java 11版本特性说明
  2. 收藏!机器学习算法分类图谱及其优缺点综合分析
  3. Python自然语言处理学习笔记(66):7.7 小结
  4. ZOJ Monthly, November 2012
  5. ZOJ 1004 Anagrams by Stack(DFS+数据结构)
  6. ElasticSearch多字段查询best_fieldsmost_fields
  7. python如何只保留数字_如何查询刷卡消费有没有积分?只需用4个数字马上能查...
  8. 软件测评师考试大纲2018
  9. ascii码值为负数_C语言编程基础学习字符型数据的ASCII码值为何是负数?
  10. 定义图书类Book,具有属性账号id,铭name.作者author和价格price,在创建图书对象时要求通过构造器进行创建,- -次性将四个属性全部赋值
  11. 军品研制过程评审活动-(一)论证阶段
  12. 学习笔记2-了解unik的设计
  13. JavaSSM-Mybatis框架使用
  14. 根据两个经纬度点调用百度地图应用查询路线 适用android或者ios中及网页浏览(手机网页同样适用)
  15. 浅谈Vue渐进式的理解
  16. 图书管理系统——C语言版
  17. GraphicConverter Mac图片浏览和编辑器
  18. TP- LINK企业级vp-n路由器ipsec场景与实施(野蛮模式)
  19. HADOOP组成部分
  20. 使用Mac的浏览器调试ios设备上的cordova app

热门文章

  1. 【开机自启动】将一个程序设为开机自启动的4种方式 (亲测)
  2. 【TSCH概述/CONTIKI】
  3. 菜鸟网管的入门之路-前言
  4. Pandas的学习之——使用Pandas进行描述性统计
  5. editable string 转_Java Editable.getSpans方法代码示例
  6. 【数字孪生百科】可视化图表知识科普——Pareto图(Pareto Chart)
  7. 2019最新Python从入门到精通之30天快速学Python项目实战(完整)
  8. Ubuntu网络图标消失,连不上网的解决办法
  9. Webug-SSRF
  10. 才子佳人与QQ游戏美女找茬外挂实现