Android 拍照、選圖、裁剪 框架 UCrop

一、所需框架

拍照、選圖框架:

   源碼地址:CircularImageView

implementation 'com.mikhaellopez:circularimageview:3.0.2'

裁剪圖框架:

   源碼地址:uCrop

implementation 'com.github.yalantis:ucrop:2.2.3'

二、效果圖 

uCrop裁剪圖

三、配置過程---乾貨!!!

1、Project->build.gradle裏配置

maven { url "https://jitpack.io" }

2、Project->app->build.gradle裏導入依賴庫

implementation 'com.github.yalantis:ucrop:2.2.3'
implementation 'com.mikhaellopez:circularimageview:3.0.2'

3、在AndroidManifest.xml加入訪問權限以及內容器

    <!--系統權限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <!--註冊主頁面Activity-->
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--註冊裁剪Activity-->
        <activity
            android:name="com.yalantis.ucrop.UCropActivity"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
        <!--註冊內容器-->
        <!--在Android 7.0開始直接讀取Uri是不安全,必須通過官方給的特定的內容器轉換成封裝的Uri對象。-->
        <provider
            android:authorities="com.example.cameraalbumtest.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
    </application>

4、創建file_paths.xml資源文件

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--//path代表共享路徑,空值代表整個SD卡都可以共享。name可以隨便取。-->
    <external-path name="my_images" path=""/>
</paths>

5、佈局文件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">

    <com.mikhaellopez.circularimageview.CircularImageView
        android:id="@+id/imageHead"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="200dp"
        android:src="@mipmap/ic_launcher"
        app:civ_border_color="#000000"
        app:civ_border_width="1dp"
        app:civ_shadow="true"
        app:civ_shadow_color="#8BC34A"
        app:civ_shadow_radius="5" />

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/imageHead"
        android:layout_marginTop="30dp"
        android:layout_toLeftOf="@id/imageHead"
        android:text="拍照" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/imageHead"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp"
        android:layout_toRightOf="@id/imageHead"
        android:text="相冊" />


</RelativeLayout>

6、MainActivity.java裏調用代碼

package com.cwang.ucropdemo;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.mikhaellopez.circularimageview.CircularImageView;
import com.yalantis.ucrop.UCrop;
import com.yalantis.ucrop.UCropActivity;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author: cwang
 * @time: 2020/3/24 16:15
 * @Description:利用框架實現拍照、從相冊選圖,裁剪圖片
 */
public class MainActivity extends Activity {
    private static final String TAG = "UCropDemo";
    public static final int TAKE_PHOTO = 1;
    public static final int CHOOSE_PHOTO = 2;
    private Button btn_take_photo, btn_choose_photo;
    private Uri imageUri;
    private CircularImageView headimageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView(); // 控件的初始化
        listener(); // 註冊監聽
    }

    /**
     * View初始化
     */
    private void initView() {
        btn_take_photo = (Button) findViewById(R.id.btn1);
        btn_choose_photo = (Button) findViewById(R.id.btn2);
        headimageView = (CircularImageView) findViewById(R.id.imageHead);
    }

    /**
     * 註冊監聽
     */
    private void listener() {
        btn_take_photo.setOnClickListener(onClickListener);
        btn_choose_photo.setOnClickListener(onClickListener);
    }

    /**
     * 點擊事件監聽
     */
    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn1: // 拍照
                    takePhoto();
                    break;

                case R.id.btn2: // 相冊
                    choosePhoto();
                    break;

                default:
                    break;
            }
        }
    };

    /**
     * 選擇拍照
     */
    private void takePhoto() {
        // 創建File(路徑,文件名字)對象,用於儲存拍照後的圖片
        // getExternalCacheDir獲取SDCard/Android/data/你的應用包名/cache/目錄,一般存放臨時緩存數據
        // getExternalFilesDir()獲取SDCard/Android/data/你的應用的包名/files/ 目錄,一般放一些長時間保存的數據
        File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
        try {
            //判斷outputImage是否文件存在
            if (outputImage.exists()) {
                outputImage.delete();
            }
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //不同Android版本進行處理
        /*
         * Android 7.0開始,直接讀取本地Uri被認爲是不安全的.
         * 低於 Android 7.0只需要將File對象轉換成Uri對象,而Uri就是標識output_image.jpg的路徑
         * 高於等於Android 7.0需要通過特定的內容容器FileProvider的getUriForFile()將File對象轉換成封裝的Uri對象
         * getUriForFile()需要三個參數,第一個Context對象,第二個任意且唯一的字符串(自己隨便取)但必須保持與你註冊裏表一致,第三個就是創建的File對象
         * 別忘了在AdnroidManifest.xml進行內容容器FileProvider的註冊,以及SD卡訪問權限
         * */
        if (Build.VERSION.SDK_INT >= 24) {
            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.cwang.ucropdemo.fileprovider", outputImage);
        } else {
            imageUri = Uri.fromFile(outputImage);
        }

        //啓動照相機
        /*通過隱式Intent啓動,並且給上個界面返回一個結果碼TAKE_PHOTO=1
         * 傳遞時最好傳路徑,直接傳File,內存太大,並且Intent傳值是有內存限制大小的*/
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, TAKE_PHOTO);
    }

    /**
     * 選擇相冊
     */
    private void choosePhoto() {
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        } else {
            openAlbum();
        }
    }

    /**
     * 打開相冊
     */
    private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOOSE_PHOTO);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openAlbum();
                } else {
                    Toast.makeText(this, "相冊打開失敗", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO: // 照相
                if (resultCode == RESULT_OK) {
                    startCrop(imageUri);//照相完畢裁剪處理
                }
                break;

            case CHOOSE_PHOTO: // 相冊
                if (resultCode == RESULT_OK) {
                    //判斷手機系統版本號
                    startCrop(data.getData());
                   /*if(Build.VERSION.SDK_INT >= 19){
                       //Android 4.4或以上處理圖片方法
                       handleImageOnKitKat(data);
                   } else {
                       //Android 4.4以下處理圖片方法
                       handleImageBeforeKitKat(data);
                   }*/
                }
                break;

            case UCrop.REQUEST_CROP: // 裁剪後的效果
                if (resultCode == RESULT_OK) {
                    Uri resultUri = UCrop.getOutput(data);
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(resultUri));
                        headimageView.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;

            case UCrop.RESULT_ERROR: // 錯誤裁剪的結果
                if (resultCode == RESULT_OK) {
                    final Throwable cropError = UCrop.getError(data);
                    handleCropError(cropError);
                }
                break;
        }
    }

    /**
     * 處理剪切失敗的返回值
     *
     * @param cropError
     */
    private void handleCropError(Throwable cropError) {
        deleteTempPhotoFile();
        if (cropError != null) {
            Toast.makeText(MainActivity.this, cropError.getMessage(), Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(MainActivity.this, "無法剪切選擇圖片", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 刪除拍照臨時文件
     */
    private void deleteTempPhotoFile() {
        File tempFile = new File(Environment.getExternalStorageDirectory() + File.separator + "output_image.jpg");
        if (tempFile.exists() && tempFile.isFile()) {
            tempFile.delete();
        }
    }

    /**
     * 圖片裁剪
     *
     * @param uri
     */
    private void startCrop(Uri uri) {
        UCrop.Options options = new UCrop.Options();
        //裁剪後圖片保存在文件夾中
        Uri destinationUri = Uri.fromFile(new File(getExternalCacheDir(), "uCrop.jpg"));
        UCrop uCrop = UCrop.of(uri, destinationUri);//第一個參數是裁剪前的uri,第二個參數是裁剪後的uri
        uCrop.withAspectRatio(1, 1);//設置裁剪框的寬高比例
        //下面參數分別是縮放,旋轉,裁剪框的比例
        options.setAllowedGestures(UCropActivity.ALL, UCropActivity.NONE, UCropActivity.ALL);
        options.setToolbarTitle("移動和縮放"); // 設置標題欄文字
        options.setCropGridStrokeWidth(2); // 設置裁剪網格線的寬度(如果設置網格設置不顯示,則沒效果)
        options.setCropFrameStrokeWidth(10); // 設置裁剪框的寬度
        options.setMaxScaleMultiplier(3); // 設置最大縮放比例
        options.setHideBottomControls(true); // 隱藏下邊控制欄
        options.setShowCropGrid(true); // 設置是否顯示裁剪網格
        options.setCircleDimmedLayer(false); // 設置是否爲圓形裁剪框
        options.setShowCropFrame(false); // 設置是否顯示裁剪邊框(true爲方形邊框)
        options.setToolbarWidgetColor(Color.parseColor("#ffffff")); // 標題字的顏色以及按鈕顏色
        options.setDimmedLayerColor(Color.parseColor("#AA000000")); // 設置裁剪外顏色
        options.setToolbarColor(Color.parseColor("#000000")); // 設置標題欄顏色
        options.setStatusBarColor(Color.parseColor("#000000")); // 設置狀態欄顏色
        options.setCropGridColor(Color.parseColor("#ffffff")); // 設置裁剪網格的顏色
        options.setCropFrameColor(Color.parseColor("#ffffff")); // 設置裁剪框的顏色
        uCrop.withOptions(options);
        uCrop.start(this);
    }

    /**
     * Android 4.4以上處理圖片方法
     *
     * @param data
     */
    @TargetApi(19)
    private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();
        if (DocumentsContract.isDocumentUri(this, uri)) {
            //如果document類型Uri,則通過document id處理
            String docId = DocumentsContract.getDocumentId(uri);
            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                String id = docId.split(":")[1];//解析數字格式的id
                String selection = MediaStore.Images.Media._ID + "=" + id;
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            //如果content類型的Uri,則使用普通的方式處理
            imagePath = getImagePath(uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            //如果是file類型的Uri,直接獲取圖片的路徑即可
            imagePath = uri.getPath();
        }
        displayImage(imagePath);//根據圖片路徑顯示圖片
    }


    /**
     * Android 4.4以下處理圖片方法
     *
     * @param data
     */
    private void handleImageBeforeKitKat(Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(uri, null);
        displayImage(imagePath);
    }

    /**
     * 獲取圖片路徑
     *
     * @param uri
     * @param selection
     * @return
     */
    private String getImagePath(Uri uri, String selection) {
        String path = null;
        //通過Uri和selection來獲取真實的圖片的路徑
        Cursor coursor = getContentResolver().query(uri, null, selection, null, null);
        if (coursor != null) {
            if (coursor.moveToFirst()) {
                path = coursor.getString(coursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            coursor.close();
        }
        return path;
    }

    /**
     * 展示圖片
     *
     * @param imagePath
     */
    private void displayImage(String imagePath) {
        if (imagePath != null) {
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            headimageView.setImageBitmap(bitmap);
        } else {
            Toast.makeText(this, "獲取圖片失敗", Toast.LENGTH_SHORT).show();
        }
    }
}

 

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