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"/>

注意:最後一句不能掉

(5) Mutate() is not supported for older platform 問題
最近在使用的時候發現報了下面這個錯誤:

這裏寫圖片描述

仔細看報錯:

Mutate() is not supported for older platform - Therefore, override color resource (ucrop_color_toolbar_widget) in your app to make it work on pre-L devices

解決方法是在color.xml中添加下面一段代碼:

<!-- UCrop colors -->
<color name="ucrop_color_toolbar_widget">@color/white</color>

如果還是無法顯示圖片,那麼請檢查你的圖片url是否能正確打開。

7 總結

經過一番折騰,終於把uCrop用上了,這個項目還是很新的,使用了Android 6.0中的victor drawable,代碼中也用到很多Android新特性,例如:註釋@NoNull等,值得去看一看作者的源碼。經過本文的講解,相信你應該已經愉快的用上了uCrop了,如果還遇到什麼問題,歡迎給我留言

8 轉載請註明來自”梧桐那時雨”的博客:http://blog.csdn.net/fuchaosz/article/details/51202264

Tips
如果覺得這篇博客對你有幫助或者喜歡博主的寫作風格,就給博主留個言或者頂一下唄,鼓勵博主創作出更多優質博客,Thank you.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章