前言
图片裁剪是对图片进行区域选定,然后裁剪选定的区域,构成一个图片,然后再对这个图片进行紧缩,终究回来效果图片。工作效果图
正文
从上面的描绘来看貌似是挺简略的是吧,不过实际操作起来就没有那么简略了,下面先来看看简略的实现方法,就是Android自带的裁剪。
一、创建并配备项目
我们仍然从创建项目开端讲起,这虽然有一些繁琐,但无疑可以让每一个Android开发者看懂。创建一个名为PictureCroppingDemo的项目。
创建好之后,在app的build.gradle添加如下代码,有两处
//JDK版别
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// google权限办理结构
implementation 'pub.devrel:easypermissions:3.0.0'
//抢手强壮的图片加载器
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
添加方位如下图所示:
然后翻开AndroidManifest.xml,在里面添加两个权限
<!--读写外部存储-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
这两个权限在Android6.0及以上版别归于风险权限,需求动态央求,下面来写权限央求的代码吧。
二、权限央求
首要在MainActivity中重写这个onRequestPermissionsResult方法。这个方法归于Android原生的权限央求回来,下面来看它的具体内容:
/**
* 权限央求效果
* @param requestCode 央求码
* @param permissions 央求权限
* @param grantResults 授权效果
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 将效果转发给 EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
EasyPermissions就是刚才在build.gradle中添加的依赖库,然后写一个权限央求的方法。
@AfterPermissionGranted(9527)
private void requestPermission(){
String[] param = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
if(EasyPermissions.hasPermissions(this,param)){
//已有权限
showMsg("已取得权限");
}else {
//无权限 则进行权限央求
EasyPermissions.requestPermissions(this,"央求权限",9527,param);
}
}
这个requestPermission()方法上面有一个注解,这个注解是什么意思嗯呢,就是权限通往后再调用一次这个方法。然后看方法里面做了什么,定义了一个字符串数组,里面有两个权限,都是在AndroidManifest.xml中配备过的,实际上这两个权限在一个权限组里面,一个权限组只需有一个权限通过则表明整组权限通过,因此你只需求放置一个权限就好了,我这么写是为了让你更清楚一些。然后是一个判别,通过这结构去判别当时的权限是否以获取,是则进行后续操作,我这儿是弹一个Toast,方法也很简略。
/**
* Toast提示
* @param msg 内容
*/
private void showMsg(String msg){
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
假如没有权限则通过下面这行代码去央求权限
EasyPermissions.requestPermissions(this,"央求权限",9527,param);
这儿的9527其实是一个央求码,它需求与注解中的对应,只需这样它在权限颁发之后才会再次调用这个方法做检测。更标准的写法是定于一个全局变量,然后替换这个9527,比如这样
/**
* 外部存储权限央求码
*/
public static final int REQUEST_EXTERNAL_STORAGE_CODE = 9527;
然后批改对应的当地即可,如下图所示:
终究记得在onCreate中调用这个requestPermission()方法。下面工作一下:
三、获取图片Uri
在上面我们现已获取到了权限,下面就来获取这个图片的Uri,然后通过图片Uri闪现这个图片。
首要批改布局activity_main.xml
<?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">
<ImageView
android:id="@+id/iv_picture"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:onClick="openAlbum"
android:text="翻开相册" />
</RelativeLayout>
很简略的布局,这儿唯一要说的就是这个onClick=”openAlbum”,假如你的按钮不需求进行设置的话,单个按钮的点击事情这样写更简练一些,你会看到这个当地有一条红线,这需求到Activity中去写这个方法,你可以通过快捷键去生成这个方法。鼠标点击这个划红线的当地,然后Alt + Enter,下面会弹出一个窗口,第二项就是说在MainActivity中创建openAlbum方法。这种方法在Fragment中并不是适用,请注意。
然后你就会在MainActivity中看到这样的方法,请注意一点,这个方法名与你onClick中的值必需求共同。
/**
* 翻开相册
*/
public void openAlbum(View view) {
}
下面来写翻开相册的方法。这儿相同的需求一个央求码,去翻开相册,然后通过回来的效果去读取图片的uri,定义一个央求码
/**
* 翻开相册央求码
*/
private static final int OPEN_ALBUM_CODE = 100;
然后在批改openAlbum方法,代码如下:
/**
* 翻开相册
*/
public void openAlbum(View view) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, OPEN_ALBUM_CODE);
}
注意这儿运用了startActivityForResult,则需求获取回来值。重写onActivityResult方法。
/**
* 回来Activity效果
*
* @param requestCode 央求码
* @param resultCode 效果码
* @param data 数据
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
这儿先获取相册中的图片闪现到Activity中,刚才在activity_main.xml中的ImageView控件就派上用场了。
//图片
private ImageView ivPicture;
然后在onCreate中绑定xml的id。下面你再运用这个ivPicture就不会报空方针了。
ivPicture = findViewById(R.id.iv_picture);
然后回到onActivityResult方法,批改代码如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == OPEN_ALBUM_CODE && resultCode == RESULT_OK) {
final Uri imageUri = Objects.requireNonNull(data).getData();
//闪现图片
Glide.with(this).load(imageUri).into(ivPicture);
}
}
这儿加了一个判别用于检测是否为翻开相册之后的回来与回来是否成功。RESULT_OK是Activity中自带的。
然后在获取数据时判空处理一下再赋值给一个Uri变量,然后通过Glide结构加载这个Url闪现在刚才的ivPicture上。代码写好了,下面工作一下:
嗯,图片闪现出来了,图片的url也拿到了,下面该做这个图片的取舍了。
四、图片裁剪
既然是调用Android系统的图片裁剪,那么天然也和翻开系统相册差不多,仍然是先创建一个央求码:
/**
* 图片取舍央求码
*/
public static final int PICTURE_CROPPING_CODE = 200;
然后写一个裁剪的方法。
/**
* 图片取舍
*
* @param uri 图片uri
*/
private void pictureCropping(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, PICTURE_CROPPING_CODE);
}
图片裁剪需求用到uri,再上面翻开相册回来时就现已拿到了uri,那么下面批改onActivityResult方法。
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == OPEN_ALBUM_CODE && resultCode == RESULT_OK) {
//翻开相册回来
final Uri imageUri = Objects.requireNonNull(data).getData();
//图片取舍
pictureCropping(imageUri);
} else if (requestCode == PICTURE_CROPPING_CODE && resultCode == RESULT_OK) {
//图片取舍回来
Bundle bundle = data.getExtras();
if (bundle != null) {
//在这儿取得了取舍后的Bitmap方针,可以用于上传
Bitmap image = bundle.getParcelable("data");
//设置到ImageView上
ivPicture.setImageBitmap(image);
}
}
}
在翻开相册回来之后调用pictureCropping方法,传入图片url,然后会发起系统取舍,取舍后通过回来数据数据设置到ImageVIew控件上。注意取舍后就不再是uri了,而是Bitmap。工作一下:
可以看到系统的取舍并不是很完全,gif中虽然演示的取舍时是一个圆形,但实际上取舍的是一个正方形的,这其实和Android系统版别及设置的参数有联系。我在荣耀8和荣耀20i上工作都是这样的,对应的版别是8.0和10.0,效果底子共同。那么下面批改一下参数试试看,如下图我批改了宽高比例和取舍后的宽高。
再工作一下:
可以看到通过该参数真的就不一样了不是吗?
但是有一些朋友想要圆形的取舍,那么这儿有一个问题你要弄清楚,你要真的仍是假的,真的圆形,那么肯定是需求取舍后从头生成的,而假的圆形就很好办了,首要我们改回刚才的参数,那么在我的是手机上就仍是这样的圆形取舍框,而我只需让他闪现出来是一个圆形,你就会认为你是取舍成功了,当然这都是忽悠用户的好方法,下面来实践一下。这个可以通过外力来处理,圆形图片许多方法能做到,比如第三方结构、自定义View等。
还记得刚才用过的Glide吗?创建requestOptions方针
/**
* Glide央求图片选项配备
*/
private RequestOptions requestOptions = RequestOptions
.circleCropTransform()//圆形取舍
.diskCacheStrategy(DiskCacheStrategy.NONE)//不做磁盘缓存
.skipMemoryCache(true);//不做内存缓存
然后在取舍图片的回来中设置图片
Glide.with(this).load(image).apply(requestOptions).into(ivPicture);
工作一下:
五、源码
源码地址:PictureCroppingDemo
结尾
OK,就到这儿了。我是初学者-Study,天长地久,后会有期。 此项目并不一定适配全部机型和Android版别,要根据实际情况就改动才行。