Android 系统自带图片裁剪功能(适配7.0、8.0、对了还有小米手机)
前段时间写了如何获取相册和拍照之后的照片并且进行显示和上传,这一次是如何进行圆形图像制作,经常看我写的笔记的人会知道,我很懒。那么我就懒的自定义了,目前需求就用原生的就好了,大神的轮子,我会在后面进行推荐。这篇笔记是依赖于: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 测试的时候,我就懵逼了,出现了如下结果:
bug
描述一下:
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—薄荷,哔哩哔哩 在使用
uCrop
2、android-crop—网易新闻,芒果TV 在使用
android-crop
3、PhotoCrop—快手 使用
PhotoCrop
4、CropBitmap—>出自一位牛x的群友
Android 系统自带图片裁剪功能(适配7.0、8.0、对了还有小米手机)的更多相关文章
- 手机调用系统的拍照和裁剪功能,假设界面有输入框EditText,在一些手机会出现点击EditText会弹出输入法,却不能输入的情况。
1. 拍照裁剪后 点击EditText会弹出输入法,却不能输入.可是点击点一EdtiText就能够输入了,所以我就写了一个看不见的EdtiText,切换焦点,这样就攻克了这个奇怪的这问题,应该是and ...
- 利用 Android 系统原生 API 实现分享功能
利用 Android 系统原生 API 实现分享功能 这篇文章提供一个封装好的 Share2 库供大家参考. GitHub 项目地址:Share2 大家知道,要调用 Android 系统内建的分享功能 ...
- jQuery.YesShow - 图片轮播插件(带图片放大功能)
jQuery.YesShow - 图片轮播插件(带图片放大功能) 使用简单,原文件只要这样就可以了:<div id="yes"> <ul> ...
- Android中实现全屏、无标题栏的两种办法(另附Android系统自带样式的解释)
在进行UI设计时,我们经常需要将屏幕设置成无标题栏或者全屏.要实现起来也非常简单,主要有两种方法:配置xml文件和编写代码设置. 1.在xml文件中进行配置 在项目的清单文件AndroidManife ...
- Android系统自带APP分析——短信app
Android操作系统本身就是一个巨大的开源软件仓库,熟悉它既可以了解到Android系统的设计框架,也可以获得高效的应用程序编写方式.本文所分析的源码来自于Google官方的AOSP源码4.0.1_ ...
- Ecmall系统自带的分页功能
在Ecmall的二次开发中,分页是必不可少的.这个系统已经自带了分页功能,下面来看看如何使用这个分页. 下面是一个自定义的类,用于查看订单的详细情况.关键在于get_order_data()这个方法, ...
- android系统自带的Service原理与使用
1. 说明 android的后台运行在很多service,它们在系统启动时被SystemServer开启,支持系统的正常工作,比如 MountService监听是否有SD卡安装及移除,Clipboar ...
- iOS实现图片裁剪功能,基于TKImageView完善与讲解
1.功能需求:需要实现图片区域裁剪功能. 2.效果图: 3.实现原理:本来想自己实现的,刚好看到一个比较好的库:TKImageView,下载好研究了下,发现基本都能满足我的需求,而且封装的也比 ...
- Android系统更新防互刷功能实现与分析【转】
本文转载自:https://blog.csdn.net/huangyabin001/article/details/44465145 版权声明:本文为博主原创文章,未经博主允许不得转载. htt ...
随机推荐
- C语言里面"具有外部链接的静态变量"这里的"链接"是什么意思
首先从静态变量说起. C语言里面静态变量有三种: 分别是外部链接性,内部链接性和无链接性.声明外部链接的变量的方法是在代码块外面声明它. 此变量是全局变量,多文件中亦可用.声明内部链接的变量的方法是在 ...
- 小学四则运算口算练习app---No.1
因为对app不是很了解,对环境的配置也不是很舒心,今天主要配置了环境,了解了一些相关app的简单操作以及安卓stdiuo的使用!如下: 我自己连接的自己的手机(还是不要拿自己的手机做测试哦!模拟器虽然 ...
- 【oracle】drop,truncate,delete用法
drop: drop table 表名:删表 truncate: truncate table 表名:清空数据 delete: delete table 表名 [where 条件]:删某数据 日志:d ...
- Educational Codeforces Round 78 (Rated for Div. 2) B - A and B(思维)
- selenium--拖拽页面元素
from selenium import webdriver import unittest from selenium.webdriver import ActionChains import ti ...
- 第02组 Alpha冲刺(2/6)
队名:無駄無駄 组长博客 作业博客 组员情况 张越洋 过去两天完成了哪些任务 任务分配.进度监督 提交记录(全组共用) 接下来的计划 沟通前后端成员,监督.提醒他们尽快完成各自的进度 还剩下哪些任务 ...
- 2018-2019-2 网络对抗技术 20165318 Exp7 网络欺诈防范
2018-2019-2 网络对抗技术 20165318 Exp7 网络欺诈防范 原理与实践说明 实践目标 实践内容概述 基础问题回答 实践过程记录 简单应用SET工具建立冒名网站 ettercap D ...
- python 统计字符串中指定字符出现次数的方法
python 统计字符串中指定字符出现次数的方法: strs = "They look good and stick good!" count_set = ['look','goo ...
- 快速排序详解(C语言/python)
快速排序详解 介绍: 快速排序于C. A. R. Hoare在1960年提出,是针对冒泡排序的一种改进.它每一次将需要排序的部分划分为俩个独立的部分,其中一个部分的数比的数都小.然后再按照这个方法对这 ...
- Jenkins绑定git
1,新建任务