实现思维路径:

以进入相机拍照的思维路线为例子:

1.进入app

2.判断之前是否保存头像,如果有就显示历史图像 (下面代码中在getOldAvatar();方法中执行这个逻辑)

3.点击更换图像的Button或者布局,启动对话框(下面代码中在dialogueBox();方法执行这个逻辑)

4.系统版本判断授权方式(静态还是动态授权),判断之前是否已经授权 (setPermissions(Permissions_CAMERA_KEY);这个方法执行授权逻辑)

5.如果是首次授权,就执行首次授权完成后马上运行的回调方法 onRequestPermissionsResult

5.判断完成不管是否是首次授权还是之前就是授权过了都要执行enterCamera();方法启动相机并且发送携带数据的请求

6.启动相机完成后,并且拍照完成退出相机,都要运行Intent返回数据请求回调方法onActivityResult。将传入的数据传入到cropPhoto(data.getData());方法里去执行图片剪裁。

7.在cropPhoto方法里将携带数据跳转到裁剪界面中裁剪图片,裁剪完成后又要回到onActivityResult回调方法里,执行裁剪完的数据回调工作。

8.在onActivityResult回调方法里,裁剪完的图片将运行setPicToView 方法保存图片。保存的图片将在下次启动activity时作为历史头像调用。

package com.example.lenovo.mydemoapp;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.Manifest; import com.example.lenovo.mydemoapp.myAppCompatActivity.MyAppCompatAcitivity;
import com.example.lenovo.mydemoapp.myLayout.TitleLayout; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; public class PersonalDataModification extends AppCompatActivity{
private static final String TAG = "PDM";
private TitleLayout mTitleLayout;
private TextView mTitleText;
private LinearLayout mPersonalDataModification_Avatar,mDialog_CameraButton,mDialog_GalleryButton;
private ImageView mPersonalDataModification_imageView_Avatar;
//得到外部存储根目录路径
private String mAvatarPath = Environment.getExternalStorageDirectory() + "/myAvatar/";
private String mAvatarName = "Avatar.jpg";
private Bitmap mBitmap;
/*
进入相册,相机,照片裁剪的key组
*/
private static final int ENTER_GALLERY = 1;
private static final int ENTER_CAMERA = 2;
private static final int ENTER_CROP_PHOTO = 3;
//需要在进入相机拍照或者相册选择图像中做区分。所以写了一个KEY来处理不同的Button
private static final int Permissions_GALLERY_KEY = 1;
private static final int Permissions_CAMERA_KEY = 2;
//需要的权限 注意请不要将数组写成 private String mPermissions[] = {"Manifest.permission.WRITE_EXTERNAL_STORAGE"};
//这样加了引号的是错误的
private String mPermissions[] = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
setContentView(R.layout.activity_personal_data_modification);
// 设置标题栏
setTitle();
//显示历史头像
getOldAvatar();
// 添加对话框
dialogueBox();
}
/*
对话框
*/
public void dialogueBox(){
mPersonalDataModification_Avatar = (LinearLayout)findViewById(R.id.PersonalDataModification_Avatar);
mPersonalDataModification_Avatar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//添加对话框
AlertDialog.Builder builder = new AlertDialog.Builder(PersonalDataModification.this);
//创建对话框 注意一定要这样写 在下面的dialog才能执行dismiss();方法
final AlertDialog dialog = builder.create();
View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.dialog_layout,null,false);
//导入视图
dialog.setView(view);
mDialog_CameraButton = (LinearLayout)view.findViewById(R.id.PersonalDataModification_Dialog_CameraButton);
mDialog_GalleryButton = (LinearLayout)view.findViewById(R.id.PersonalDataModification_Dialog_GalleryButton);
//相机
mDialog_CameraButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//设置权限
setPermissions(Permissions_CAMERA_KEY);
//关闭对话框
dialog.dismiss();
}
});
//相册
mDialog_GalleryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setPermissions(Permissions_GALLERY_KEY);
dialog.dismiss();
}
});
//创建并且显示
dialog.show();
}
});
}
public void setPermissions(int mPermissions_KEY){
/*
要添加List原因是想判断数组里如果有个别已经授权的权限,就不需要再添加到List中。添加到List中的权限后续将转成数组去申请权限
*/
List<String> permissionsList = new ArrayList<>();
//判断系统版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (int i = 0; i < mPermissions.length; i++) {
//判断一个权限是否已经允许授权,如果没有授权就会将单个未授权的权限添加到List里面
if (ContextCompat.checkSelfPermission(this.getApplicationContext(), mPermissions[i]) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(mPermissions[i]);
}
}
//判断List不是空的,如果有内容就运行获取权限
if (!permissionsList.isEmpty()) {
String [] permissions = permissionsList.toArray(new String[permissionsList.size()]);
for (int j=0;j<permissions.length;j++){
Log.e(TAG,permissions[j]);
}
Log.e(TAG,"需要授权的权限有:"+permissions.length+"条");
//执行授权的代码。此处执行后会弹窗授权
ActivityCompat.requestPermissions(this, permissions, mPermissions_KEY);
} else { //如果是空的说明全部权限都已经授权了,就不授权了,直接执行进入相机或者图库
switch (mPermissions_KEY) {
case Permissions_CAMERA_KEY:
enterCamera();
break;
case Permissions_GALLERY_KEY:
enterGallery();
break;
default:
break;
}
}
}else {
Toast.makeText(getBaseContext(), "6.0以下的版本无需授权", Toast.LENGTH_SHORT).show();
Log.e(TAG,"6.0以下的版本无需授权");
switch (mPermissions_KEY) {
case Permissions_CAMERA_KEY:
enterCamera();
break;
case Permissions_GALLERY_KEY:
enterGallery();
break;
default:
break;
}
}
}
/*
授权完成后马上会运行的回调方法,此处写入首次授权完成后,要运行的内容
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == Permissions_CAMERA_KEY) {
if (grantResults.length > 0) { //安全写法,如果小于0,肯定会出错了
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "全部权限都成功授权进入相机");
enterCamera();
} else {
finish();
Toast.makeText(getBaseContext(), "授权失败", Toast.LENGTH_SHORT).show();
Log.e(TAG, "相机授权失败");
}
}
}
} else if (requestCode == Permissions_GALLERY_KEY) {
if (requestCode == Permissions_GALLERY_KEY) {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "全部权限都成功授权进入相册");
enterGallery();
} else {
finish();
Toast.makeText(getBaseContext(), "授权失败", Toast.LENGTH_SHORT).show();
Log.e(TAG, "相册授权失败");
}
}
}
}
}
}
/*
点击后进入相机
*/
public void enterCamera(){
//MediaStore 多媒体存储 ACTION行动 IMAGE 图片 CAPTURW捕获
Intent intentGallery = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
/* 多媒体存储,额外制造 从文件里获取路径(获取外部存储目录 图片名称head.jpg)
将图片设置名称并且保存到外部存储空间里
*/
intentGallery.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(Environment.getExternalStorageDirectory(), mAvatarName)));
//跳转页面启动相册,携带数据请求码
startActivityForResult(intentGallery,ENTER_CAMERA);
}
/*
点击后进入相册
*/
public void enterGallery(){
Intent intentCamera = new Intent(Intent.ACTION_PICK,null);
//设置数据和类型 多媒体存储.图片.媒体.外部.内容.URI image/*图片格式
intentCamera.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(intentCamera, ENTER_GALLERY); }
/*
从Intent中返回请求数据的方法,活动退出后运行这个方法
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
/*
相册选中图片后的数据回调
*/
case ENTER_GALLERY:
if(resultCode == RESULT_OK){
cropPhoto(data.getData());
}
break;
/*
拍照完成后的数据回调
*/
case ENTER_CAMERA:
if (resultCode == RESULT_OK) {
File temp = new File(Environment.getExternalStorageDirectory() + "/"+mAvatarName);
cropPhoto(Uri.fromFile(temp));// 裁剪图片 cropPhoto 200行方法
}
break;
/*
裁剪完成后的数据回调
*/
case ENTER_CROP_PHOTO:
if (data.resolveActivity(getPackageManager())!=null) {//判断Intent是否为空
Bundle extras = data.getExtras();
mBitmap = extras.getParcelable("data");
if (mBitmap != null) {
setPicToView(mBitmap);// 保存在SD卡中
mPersonalDataModification_imageView_Avatar.setImageBitmap(mBitmap);// 用ImageButton显示出来
}
}
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
/*
调用系统的裁剪功能,进入裁剪页面
*/
public void cropPhoto(Uri uri){
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri,"image/*");
intent.putExtra("crop","ture");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
intent.putExtra("outputX", 250);
intent.putExtra("outputY", 250);
intent.putExtra("return-data", true);
Log.e(TAG,"头像裁剪");
startActivityForResult(intent, ENTER_CROP_PHOTO);
}
/*
显示默认头像或者历史设置的头像
*/
public void getOldAvatar(){
mPersonalDataModification_imageView_Avatar = (ImageView)findViewById(R.id.PersonalDataModification_imageView_Avatar);
//从文件存储里得到图片
Bitmap bt = BitmapFactory.decodeFile(mAvatarPath+mAvatarName);
//判断不是空头像
if (bt != null){
Drawable drawable = new BitmapDrawable(getResources(),bt);
//重新设置头像图片 注意这里使用的是setImageDrawable,不是setImageResource
mPersonalDataModification_imageView_Avatar.setImageDrawable(drawable);
Log.e(TAG,"使用历史头像");
}else {
//如果没有旧的头像就使用系统默认的
mPersonalDataModification_imageView_Avatar.setImageResource(R.drawable.ic_woman_default);
Log.e(TAG,"使用默认头像");
}
}
/*
保存到sd卡是为了下一次进入apk的时候直接读取图片,
*/
private void setPicToView(Bitmap mBitmap) {
String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
return;
} try {
File dir = new File(mAvatarPath);
dir.mkdirs();// 创建文件夹
File file = new File(mAvatarPath, mAvatarName);
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream b = new FileOutputStream(file);
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把图片数据写入图片b
b.flush(); //刷新
b.close(); //关闭
}catch(IOException e){
e.printStackTrace();
}
/*
FileOutputStream b = null;
File file = new File(mAvatarPath);
file.mkdirs();// 创建文件夹
String fileName = mAvatarPath + mAvatarName;// 图片名字
try {
b = new FileOutputStream(fileName);
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把图片数据写入图片b
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush(); //刷新
b.close(); //关闭
} catch (IOException e) {
e.printStackTrace();
}
}
*/
}
}

android 开发 实现一个进入相机拍照后裁剪图片或者进入相册选中裁剪图片的功能的更多相关文章

  1. Android开发工程师文集-Fragment,适配器,轮播图,ScrollView,Gallery 图片浏览器,Android常用布局样式

    Android开发工程师文集-Fragment,适配器,轮播图,ScrollView,Gallery 图片浏览器,Android常用布局样式 Fragment FragmentManager frag ...

  2. 2016 校招, Android 开发,一个本科应届的坎坷求职之路(转)

    转载出处:http://www.nowcoder.com/discuss/3244?type=2&order=0&pos=1&page=1 和大多数的面经不同,我不是大牛,手头 ...

  3. android 开发 实现一个app的引导查看页面(使用ViewPager组件)

    我们安装完app后第一次打开app,通常都会有一个翻页图片形式的app引导简介说明.下面我们来实现这个功能.ViewPager这个组件与ListView和RecyclerView在使用上有很高的相似处 ...

  4. Android笔记之调用系统相机拍照

    参考链接: 拍照  |  Android Developers, Android相机拍照方向旋转的解决方案:ExifInterface - 简书 Demo链接:https://pan.baidu.co ...

  5. android 自定义用相机拍照后的照片存储位置

    1.imageUri = Uri.fromFile(new File(Environment .getExternalStorageDirectory()+ File.separator + getP ...

  6. android 相机拍照后选择照片编辑,相片编辑界面直线形状会显示锯齿状

    因为 decode 出来的图片太小,小于屏幕.所以,显示的时候 会把图片略微放大,导致直线形状会显示锯齿状.   能够改动getScreenImageSize 方法中的size 的大小,比方能够把13 ...

  7. android开发 无预览定时拍照

    demo实现功能: 打开主页面自动启动定时拍照,10s拍一次. 注意事项,初始化摄像头之后不能立即拍照,否则无效,必须等待几秒后才能拍.这里用的是Handler进行延时处理拍照消息的. package ...

  8. android 开发 实现一个自定义布局的AlertDialog对话框

    对话框有很多实现方法,最常见的是在一个点击事件中代码直接写出对话框.如下: package com.example.lenovo.mydemo2; import android.content.Dia ...

  9. 记录 android 开发的一个 "面试" 问题

    前序: 3天前,有幸得到师兄赏识,和他一起去帮一间珠海的本地的IT公司担任面试官,虽说如此,我自己本身就还没毕业,充其量是去见识下世面罢了.当天共面试了13人,这只是上午,下午我闪了.在笔试的部分,我 ...

随机推荐

  1. 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

    问题 rds_content = "{}, 执行了变更,sql语句:{}".format(ExecuteTime, sqls) 'ascii' codec can't encode ...

  2. java 多线程详解

    一.重点 重点: 1.创建和启动线程 2.实现线程调度 3.实现线程同步 4.实现线程通信 1.为什么要学习多线程? 当多个人访问电脑上同一资源的时候,要用到多线程,让每个人感觉很多电脑同时为多个人服 ...

  3. Simple Logging Facade for Java 简单日志门面(Facade)

    SLF4J是为各种 loging APIs提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的loging APIs实现.Logging API实现既可以选择直接实现SLF4J接口的 ...

  4. 关于信号的延迟---verilog

    关于信号的延迟---verilog `timescale 1ns / 1ps ///////////////////////////////////////////////////////////// ...

  5. HDMI初识

    HDMI初识 1.阅读文档xapp1287 (1) KC705 HDMI Reference Design Block Diagram (2) KC705 HDMI Reference Design ...

  6. [转]python实现RESTful服务(基于flask)

    python实现RESTful服务(基于flask) 原文: https://www.jianshu.com/p/6ac1cab17929  前言 上一篇文章讲到如何用java实现RESTful服务, ...

  7. TdxMemData 的Bug和使用

    aa.CopyFromDataSet(acdsBase);//克隆一个,与LoadFromDataSet区别,如果设置了Field,那么L只会导入设置的部分,而C则是全部复制过来 TdxMemData ...

  8. FastReport 保存为文件

    public void SaveToPDF<TModel>(List<TModel> model, string content, string saveFilePath) { ...

  9. sql中的STRFTIME

    STRFTIME返回的是一个字符串 STRFTIME('%w',myTime) in ('1','2','4','5') 可以正确执行,而 STRFTIME('%w',myTime) in (1,2, ...

  10. HP Gen8,9 型号系列服务器更换主板

    更换主板前,记下如下信息,根据具体情况用于更换后的设置用.1.S/N (其实主机箱上会写有,更换后重置)2.ProductID (其实主机箱上会写有,更换后重置)3.iLO IP地址或者MAC地址(根 ...