实现思维路径:

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

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. PHP破解wifi密码(wifi万能钥匙的接口)

    新建wifi.php,复制粘贴 <?php $bssid = $_POST["bssid"] ; $ssid = $_POST["ssid"] ; if ...

  2. ML: 降维算法-PCA

            PCA (Principal Component Analysis) 主成份分析 也称为卡尔胡宁-勒夫变换(Karhunen-Loeve Transform),是一种用于探索高维数据结 ...

  3. MySQL Master High Available 源码篇

    https://m.aliyun.com/yunqi/users/1287368569594542/articles https://yq.aliyun.com/articles/59233 MySQ ...

  4. Linux bash笔记

    关于bash脚本,一般开头都加#!/bin/bash,表示以bash来作为脚本解释器:如果不加的话,就会默认当前用户登陆的shell为脚本解释器(很多情况下为sh,sh与bash不同,有可能导致脚本无 ...

  5. Python如何查询Mysql

    Python查询Mysql使用 fetchone() 方法获取单条数据, 使用fetchall() 方法获取多条数据. fetchone(): 该方法获取下一个查询结果集.结果集是一个对象 fetch ...

  6. Windump教程-参数介绍

    1 应用 Windump是tcpdump的Windows版本,主要的参数如下: -D 列出所有的接口 -i interface 指定用于抓包的接口 -c packetcount 指定抓包的个数 -w ...

  7. Windowsx64位安装pymssql并完成与数据库链接

    常流程只需要打开下载并按照常规方法安装mssql包即可在程序中import pymssql,不过安装mssql确实有些小麻烦. 从开始安装就开始出现了各种异常错误 首先出现sqlfront.h文件找不 ...

  8. 理解 neutron(15):Neutron Linux Bridge + VLAN/VXLAN 虚拟网络

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  9. CDlinux 安装

    镜像 CDlinux-0.9.7.1 虚拟机VMware12 1.VMware12中,新建虚拟机 2.典型安装方式 下一步 3.稍后安装操作系统 4.内核版本要选择[其他linux2.6.X内核] 5 ...

  10. [UE4]行为树,组合节点:Selector和Sequence

    行为树节点 一.Composite组合节点: 1.Selector 要求比较低:只要有一个子节点成功就可以了. 只要子节点有一个返回true,则停止执行其它子节点,并且Selector返回true.如 ...