Android 图片裁切框架 uCrop 的用法

1 uCrop简介

最近项目中用到了图片裁剪功能,于是百度了一下,发现了uCrop这个框架,这个框架的星星数很多,就决定使用这个框架

uCrop的Github地址:https://github.com/Yalantis/uCrop

uCrop的特点:

  1. 裁剪框不动,图片动
  2. 图片可以旋转,缩放
  3. 支持各种比例裁剪框

uCrop的效果图(来自其Github):

2 集成uCrop

(1) uCrop集成方法:

compile ‘com.yalantis:ucrop:1.4.1‘

(2) 修改当前项目的build.gradle文件,修改后代码如下:

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.test"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    ....
}

dependencies {
    compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
    compile ‘com.android.support:appcompat-v7:23.3.0‘
    compile ‘com.yalantis:ucrop:1.4.1‘
}

注意:修改了targetSdkVersion后com.android.support:appcompat-v7的版本也要相匹配

虽然使用maven依赖的话即使appcompat-v7的版本不匹配也没有关系,但使用aar文件则会报错,所以建议你修改了compileSdkVersion 后也要修改appcompat-v7的版本,搞不好就会遇到问题

(3) 如果你没有23版本的sdk,也就是Android 6.0的sdk,则要启动sdk manger去下载,同时也要下载Android SDK Build-tools 23.0.2,如下图:

(4) 修改gradle插件的版本

修改整个project最外面的全局build.gradle文件的gradle版本:

 dependencies {
        classpath ‘com.android.tools.build:gradle:2.0.0‘
 }

(5) 下载最新的gradle

Gradle下载地址:http://services.gradle.org/distributions

目前最新版本是gradle-2.13-rc-2-all.zip,下载完成后解压,然后在Android Studio中指定gradle的地址,如下图所示:

要使用2.0以上版本的gradle插件,必须使用2.10以上的gradle,注意gradle插件和gradle是两个东西,前者是Android Studio的插件,后者是独立的东西

(6) 准备工作完毕,同步代码,uCrop已经集成到我们的项目中去了,是不是很麻烦?不然我写这篇文章干嘛。

注意:uCrop必须使用23及以上版本的sdk,gradle插件版本必须2.0.0及以上,gradle版本必须2.10及以上,appcompat-v7版本必须23.0及以上

如果以上都满足了,应该就不会报错了。至于为什么非要23以上的sdk,因为uCrop使用了Android 6.0的新特性:VectorDrawable

3 uCrop的用法

(1) 在AndroidManifest.xml中添加UCropActivity,代码如下:

    <activity
            android:name="com.yalantis.ucrop.UCropActivity"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

(2) 在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>

(3) MainActivity代码如下:

public class MainActivity extends Activity {

    Button btnTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnTest = (Button) findViewById(R.id.btn_test);
        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startCrop();
            }
        });

    }

    private void startCrop() {
        Uri sourceUri = Uri.parse("http://star.xiziwang.net/uploads/allimg/140512/19_140512150412_1.jpg");
        //裁剪后保存到文件中
        Uri destinationUri = Uri.fromFile(new File(getCacheDir(), "SampleCropImage.jpeg"));
        UCrop.of(sourceUri, destinationUri).withAspectRatio(16, 9).withMaxResultSize(300, 300).start(this);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            //裁切成功
            if (requestCode == UCrop.REQUEST_CROP) {
                Uri croppedFileUri = UCrop.getOutput(data);
                //获取默认的下载目录
                String downloadsDirectoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                String filename = String.format("%d_%s", Calendar.getInstance().getTimeInMillis(), croppedFileUri.getLastPathSegment());
                File saveFile = new File(downloadsDirectoryPath, filename);
                //保存下载的图片
                FileInputStream inStream = null;
                FileOutputStream outStream = null;
                FileChannel inChannel = null;
                FileChannel outChannel = null;
                try {
                    inStream = new FileInputStream(new File(croppedFileUri.getPath()));
                    outStream = new FileOutputStream(saveFile);
                    inChannel = inStream.getChannel();
                    outChannel = outStream.getChannel();
                    inChannel.transferTo(0, inChannel.size(), outChannel);
                    Toast.makeText(this, "裁切后的图片保存在:" + saveFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        outChannel.close();
                        outStream.close();
                        inChannel.close();
                        inStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        //裁切失败
        if (resultCode == UCrop.RESULT_ERROR) {
            Toast.makeText(this, "裁切图片失败", Toast.LENGTH_SHORT).show();
        }
    }

}

主界面layout\activity_main.xml上就一个按钮,不贴出代码了

(4) 调用uCrop去裁切的方法

Uri sourceUri = Uri.parse("http://star.xiziwang.net/uploads/allimg/140512/19_140512150412_1.jpg");
        //裁剪后保存到文件中
        Uri destinationUri = Uri.fromFile(new File(getCacheDir(), "SampleCropImage.jpeg"));
        UCrop.of(sourceUri, destinationUri).withAspectRatio(16, 9).withMaxResultSize(300, 300).start(this);

本例中是从网上下载一张图片,裁切后保存到本地

(5) 获取裁切后的图片代码如下

//裁切成功
if (requestCode == UCrop.REQUEST_CROP) {
                Uri croppedFileUri = UCrop.getOutput(data);
                //获取默认的下载目录
                String downloadsDirectoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                String filename = String.format("%d_%s", Calendar.getInstance().getTimeInMillis(), croppedFileUri.getLastPathSegment());
                File saveFile = new File(downloadsDirectoryPath, filename);
                //保存下载的图片
                FileInputStream inStream = null;
                FileOutputStream outStream = null;
                FileChannel inChannel = null;
                FileChannel outChannel = null;
                try {
                    inStream = new FileInputStream(new File(croppedFileUri.getPath()));
                    outStream = new FileOutputStream(saveFile);
                    inChannel = inStream.getChannel();
                    outChannel = outStream.getChannel();
                    inChannel.transferTo(0, inChannel.size(), outChannel);
                    Toast.makeText(this, "裁切后的图片保存在:" + saveFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        outChannel.close();
                        outStream.close();
                        inChannel.close();
                        inStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

重写onActivityResult()方法,通过data获取返回的uri,再从uri中取得裁切后的文件地址,然后保存到本地

注意:要获取裁切后的uri,必须使用 Uri croppedFileUri = UCrop.getOutput(data),不能使用 Uri uri = data.getData()否则会报空指针错误

如果裁切失败,代码如下:

 //裁切失败
        if (resultCode == UCrop.RESULT_ERROR) {
            Toast.makeText(this, "裁切图片失败", Toast.LENGTH_SHORT).show();
        }

4 效果图

5 使用aar遇到的问题

为什么建议使用aar文件,而不是maven依赖,请参考我的这篇博客:

[Android Studio系列(三)]Android Studio 编译、同步慢的解决方法

如何下载uCrop的aar文件也请参考我上面这篇博客,目前下载的最新的uCrop的aar文件是ucrop-1.4.1.aar

如果使用uCrop的aar文件的话,可能会遇到下面的问题:

仔细看报的错:

Error:(35) No resource identifier found for attribute ‘srcCompat‘ in package ‘com.test3‘

百度了半天,也没有找到原因,最后模仿uCrop的demo修改了appcompat-v7的版本,解决了问题,经过实践,appcompat-v7应该修改为如下代码:

compile ‘com.android.support:appcompat-v7:23.3.0‘

6 其他可能遇到的问题

(1) sdk版本太低

仔细看,发现报下面两个错:

Error:(2) Error retrieving parent for item: No resource found that matches the given name ‘android:TextAppearance.Material.Widget.Button.Inverse’.

Error:(2) Error retrieving parent for item: No resource found that matches the given name ‘android:Widget.Material.Button.Colored’.

报这两个错的原因是: values-23是API 23(Android 6.0)中的资源文件,也就是说我们的sdk版本太低了。查看uCrop给出的例子发现确实是我们的版本太低了, uCrop的示例中build.gradle文件地址如下:

https://github.com/Yalantis/uCrop/blob/master/sample/build.gradle

(2) gradle插件版本太低

仔细看,报错:

Caused by: org.xmlpull.v1.XmlPullParserException: Binary XML file line #1: invalid drawable tag vector

at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:933)

如果sdk已经是23了,运行时报下面的错,就是gradle插件版本没有达到2.0的原因,解决方法是:classpath ‘com.android.tools.build:gradle:2.0.0‘

(3) gradle版本太低

仔细看,报错:

Error:Gradle version 2.10 is required. Current version is 2.8. If using the gradle wrapper, try editing the distributionUrl in D:\AndroidStudioProjects\Hello7\gradle\wrapper\gradle-wrapper.properties to gradle-2.10-all.zip

Fix Gradle wrapper and re-import project
Gradle settings

一看就明白是gradle版本太低了,按照第2步去下载最新的gradle,然后在Android Studio中指定即可

(4) 引入UCropActivity不当导致action bar报错

仔细看,报错:

Caused by: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.

原因是,在AndroidManifest.xml中UCropActivity时掉了android:theme="@style/Theme.AppCompat.Light.NoActionBar"这句话,正确的引入代码是:

<activity
            android:name="com.yalantis.ucrop.UCropActivity"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

注意:最后一句不能掉

7 总结

经过一番折腾,终于把uCrop用上了,这个项目还是很新的,使用了Android 6.0中的victor drawable,代码中也用到很多Android新特性,例如:注释@NoNull等,值得去看一看作者的源码。经过本文的讲解,相信你应该已经愉快的用上了uCrop了,如果还遇到什么问题,欢迎给我留言

8 转载请注明来自”梧桐那时雨”的博客:http://blog.csdn.net/fuchaosz/article/details/51202264

Tips

如果觉得这篇博客对你有帮助或者喜欢博主的写作风格,就给博主留个言或者顶一下呗,鼓励博主创作出更多优质博客,Thank you.

时间: 2024-11-03 03:34:57

Android 图片裁切框架 uCrop 的用法的相关文章

android图片缓存框架Android-Universal-Image-Loader(二)

这篇打算直接告诉大家怎么用吧,其实这个也不是很难的框架,大致使用过程如下: // 获取缓存图片目录 File cacheDir = StorageUtils.getOwnCacheDirectory(activity, "imageloader/Cache"); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder( activity).memoryCacheExtraOptions(800, 76

android图片缓存框架Android-Universal-Image-Loader

最近跟同学们做了一个创业项目,其实跟以前做项目不同,以前大多数都是做web网站,对内存管理这些不太关注,因为是pc机,做android的话也就是一些小列子,现在到了做产品阶段吧,只能把项目做到最优.不扯了,先来说这个框架是做什么的,Android-Universal-Image-Loader主要是一个图片的缓存框架,根据官方解释就是,它提供了一个异步处理图片的方案.它提供两种获取图片方式async or sync,并且提供了一个可定制化的组件(thread executors, download

图片会说话系列之Android图片缓存框架

前言:看过很多精彩的文章,作者写的非常好,但总觉得文字描述没有图片或图表说明来得直观,因为图片可以化抽象为具体.语言是有区域性的,而图片则是全世界通用的,即使语言不通,却能通过图片了解一切.因此想做一个系列的简博客,内容就是一张图附带一些必要的说明,这样就能迅速抓住重点,而不需要做太多的阅读,便能了解框架性的东西.文章所涉及到的图片有的可能来自官方网站,有的来自名家博客,或者是自己绘制的,都会一一说明. 切入正题,先来第一发,上图: 上图来自:https://github.com/nostra1

常用 Android 图片处理框架的比较

Fresco 12,324星星 https://github.com/facebook/fresco FaceBook出品,支持Android 2.3 (Gingerbread)及以上 尼玛,他竟然有专门的中文文档:https://www.fresco-cn.org/docs/index.html 添加依赖 //添加依赖 compile 'com.facebook.fresco:fresco:1.2.0' //**************下面的依赖需要根据需求添加****************

详细讲解Android图片下载框架UniversialImageLoader之内存缓存扩展(四)

内存缓存的扩展还是蛮重要的,无论是数据结构还是具体的实现还是值得我们进行细细的品味,下面咱们就一起能品味这里面的趣味吧. 内存缓存的扩展主要学习下面的几个类:FIFOLimitedMemoryCache.FuzzyKeyMemoryCache. LargestLimitedMemoryCache.LimitedAgeMemoryCache.LRULimitedMemoryCache. LruMemoryCache.UsingFreqLimitedMemoryCache以及WeakMemoryCa

具体解说Android图片下载框架UniversialImageLoader之内存缓存(三)

前面的两篇文章着重介绍的是磁盘缓存,这篇文章主要是解说一下内存缓存.对于内存缓存.也打算分两篇文章来进行解说.在这一篇文章中,我们主要是关注三个类, MemoryCache.BaseMemoryCache以及LimitedMemoryCache. 首先我们先看一下内存缓存的接口MemoryCache. put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(String key); Collection<Strin

详细讲解Android图片下载框架UniversialImageLoader之内存缓存(三)

前面的两篇文章着重介绍的是磁盘缓存,这篇文章主要是讲解一下内存缓存.对于内存缓存,也打算分两篇文章来进行讲解.在这一篇文章中,我们主要是关注三个类, MemoryCache.BaseMemoryCache以及LimitedMemoryCache. 首先我们先看一下内存缓存的接口MemoryCache. [java] view plaincopyprint? put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(S

Android 图片加载框架Universal-Image-Loader源码解析

Universal-Image-Loader(项目地址)可以说是安卓知名图片开源框架中最古老.使用率最高的一个了.一张图片的加载对于安卓应用的开发也许是件简单的事,但是如果要同时加载大量的图片,并且图片用于ListView.GridView.ViewPager等控件,如何防止出现OOM.如何防止图片错位(因为列表的View复用功能).如何更快地加载.如何让客户端程序员用最简单的操作完成本来十分复杂的图片加载工作,成了全世界安卓应用开发程序员心头的一大难题,所幸有了Universal-Image-

Android 获取并显示远程图片 Picasso框架的使用(一)

转载请注明出处:明桑Android 在Android开发中,常需要从远程获取图片并显示在客户端,当然我们可以使用原生HttpUrlConnection和AsyncTask等操作来完成,但并不推荐,因为这样不仅需要我们编写大量的代码,还需要处理缓存和下载管理等,最好自己封装成库或者采用第三方库: Picasso:A Powerful Image Downloading and Caching Library for Android 根据名字就知道它是跟什么相关了(Picasso:毕加索)它的基本操