Android 用MultiImageSelector實現上傳頭像的拍照跟相簿

騷劍客發表於2016-06-20

最近在公司做一個APP,想要實現拍照或則相簿裁剪圖片的功能

上網查閱了很多資料,然後對其一一做了測試,可是後來發現在小米手機上的裁剪方面沒有起作用,而且還閃退.
後來終於發現了原來是沒有新增:  intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

這也是網上很多資料沒有加這句話的原因把,才可能導致有部分文章沒有新增.

後來覺得應該做的比較完善點,想實現微信上類似頭像在相簿中選擇的那種效果,最後功夫不負有心人,然我在github上找到了MultiImageSelector框架可以實現這種微信效果


後來我把三大方法進行了一個封裝成一個工具類,很方便的可以進行使用

原始碼下載

PhotoOrCropUtil.class
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import me.nereo.multi_image_selector.MultiImageSelectorActivity;

/**
 * Created by shaolin on 6/17/16.
 */
public class PhotoOrCropUtil {

    private static final String TAG = "PhotoOrCropUtil";

    private static final int PHOTO_REQUEST_GALLERY = 1;
    private static final int PHOTO_REQUEST_CAREMA = 2;
    private static final int PHOTO_REQUEST_CUT = 3;
    private static final String PHOTO_FILE_NAME = "image";

    private File tempFile = new File(Environment.getExternalStorageDirectory(), PHOTO_FILE_NAME);
    private Uri imageUri = null;
    //    存放圖片路徑的list
    private ArrayList<String> mSelectPath;
    private static PhotoOrCropUtil mInstance;
    private Context mContext;
    private PhotoOrCropListener mListener;

    public static synchronized PhotoOrCropUtil getInstance() {
        if (mInstance == null) {
            mInstance = new PhotoOrCropUtil();
        }
        return mInstance;
    }

    public void setContext(Context context) {
        mContext = context;
    }

    /*
    * 從相簿獲取
    */
    public void gallery() {
        Intent intent = new Intent(mContext, MultiImageSelectorActivity.class);
        // 是否顯示拍攝圖片
        intent.putExtra(MultiImageSelectorActivity.EXTRA_SHOW_CAMERA, true);
        // 最大可選擇圖片數量
        intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_COUNT, 9);
        // 選擇模式
        intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_MODE, MultiImageSelectorActivity.MODE_SINGLE);
        // 預設選擇
        if (mSelectPath != null && mSelectPath.size() > 0) {
            intent.putExtra(MultiImageSelectorActivity.EXTRA_DEFAULT_SELECTED_LIST, mSelectPath);
        }
        ((Activity) mContext).startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
    }

    /*
     * 從相機獲取
     */
    public void camera() {
        // 啟用相機
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        // 判斷儲存卡是否可以用,可用進行儲存
        if (hasSdcard()) {
            // 從檔案中建立uri
            Uri uri = Uri.fromFile(tempFile);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        }
        // 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CAREMA
        ((Activity) mContext).startActivityForResult(intent, PHOTO_REQUEST_CAREMA);
    }

    /*
     * 剪下圖片
     */
    private void crop(Uri uri) {
        Log.e(TAG, "tempFile:" + tempFile.toString());
        Log.e(TAG, "uri:" + uri.toString());
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        //傳送裁剪訊號
        intent.putExtra("crop", "true");
        // aspectX aspectY 是寬高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪圖片寬高
        intent.putExtra("outputX", 100);
        intent.putExtra("outputY", 100);
        intent.putExtra("scale", true);
        intent.putExtra("return-data", false);
        // 將圖片裁剪儲存在一個路徑下,後面在刪除掉
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
        imageUri = Uri.fromFile(tempFile);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true); // no face detection
        // 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CUT
        ((Activity) mContext).startActivityForResult(intent, PHOTO_REQUEST_CUT);
    }

    public static boolean hasSdcard() {
        return Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState());
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PHOTO_REQUEST_GALLERY) {
            // 從相簿返回的資料
            if (data != null) {
                // 得到圖片的全路徑
                mSelectPath = data.getStringArrayListExtra(MultiImageSelectorActivity.EXTRA_RESULT);
                StringBuilder sb = new StringBuilder();
                for (String p : mSelectPath) {
                    sb.append(p);
                }
                crop(Uri.parse("file://" + sb.toString()));
            }
        } else if (requestCode == PHOTO_REQUEST_CAREMA) {
            // 從相機返回的資料
            if (hasSdcard()) {
                crop(Uri.fromFile(tempFile));
            } else {
                showToast("未找到儲存卡,無法儲存照片!");
            }
        } else if (requestCode == PHOTO_REQUEST_CUT) {
            // 從剪下圖片返回的資料
            if (resultCode == ((Activity) mContext).RESULT_OK) {
                if (imageUri != null) {
                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), imageUri);
                        mListener.uploadAvatar(bitmap);
                        imageUri = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                imageUri = null;
            }
            try {
                // 將臨時檔案刪除
                tempFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void setPhotoOrCropListener(PhotoOrCropListener listener) {
        mListener = listener;
    }

    public interface PhotoOrCropListener {
        void uploadAvatar(Bitmap bitmap);
    }

    private void showToast(String message) {
        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
    }
}
這裡注意的是匯入框架MultiImageSelector,也在上面用到MultiImageSelectorActivity,所以要在AndroidManifest.xml引用它
<activity
            android:configChanges="orientation|screenSize"
            android:name="me.nereo.multi_image_selector.MultiImageSelectorActivity" />
最後附上MainActivity例子
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;


public class MainActivity extends Activity implements View.OnClickListener {

    private Button mBtn1;
    private Button mBtn2;
    private ImageView mImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBtn1 = (Button) findViewById(R.id.button1);
        mBtn2 = (Button) findViewById(R.id.button2);
        mImage = (ImageView) findViewById(R.id.img);

        mBtn1.setOnClickListener(this);
        mBtn2.setOnClickListener(this);

        PhotoOrCropUtil.getInstance().setContext(this);
        PhotoOrCropUtil.getInstance().setPhotoOrCropListener(new PhotoOrCropUtil.PhotoOrCropListener() {
            @Override
            public void uploadAvatar(Bitmap bitmap) {
                mImage.setImageBitmap(bitmap);
            }
        });
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button1:
                PhotoOrCropUtil.getInstance().camera();
                break;
            case R.id.button2:
                PhotoOrCropUtil.getInstance().gallery();
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        PhotoOrCropUtil.getInstance().onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拍照" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="相簿" />

    <ImageView
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sourceforge.photo">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:configChanges="orientation|screenSize"
            android:name="me.nereo.multi_image_selector.MultiImageSelectorActivity" />
    </application>

</manifest>






相關文章