一、所需框架
拍照、選圖框架:
源碼地址:CircularImageView
implementation 'com.mikhaellopez:circularimageview:3.0.2'
裁剪圖框架:
源碼地址:uCrop
implementation 'com.github.yalantis:ucrop:2.2.3'
二、效果圖
三、配置過程---乾貨!!!
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();
}
}
}