Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ArthurHub/Android-Image-Cropper 相冊裁剪框架學習

ArthurHub/Android-Image-Cropper 相冊裁剪框架學習

編輯:關於Android編程

以前寫過2篇關於相冊選取、裁剪的demo,今天我們來學習下github上一款開源的相冊裁剪開源庫

開源庫地址 https://github.com/ArthurHub/Android-Image-Cropper

首先我先說下這個開源庫需要添加的東東

 

\

上面截圖中CropImage可以不用,我代碼中用的自己的圓角代碼

 

 

 
    Rotate counter clockwise
    Rotate
    Crop
    Select source
上面是string幾個string 字體(我直接就從作者的開源代碼中直接拿過來的)

 

還有attrs.xml中需要的屬性

 

 
        
            
            
            
        
        
            
            
            
            
        
        
            
            
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

基本上這個開源庫,就需要這些東東就行了

 

 

今天我們就寫一個小例子,來學習下,能夠將代碼跑起來,就ok了

 

首先看我代碼中的主布局文件,很簡單,只有一個圓角控件,點擊它以後,就掉系統的相冊應用

 



    

        
    

 

 


在MainActivity中是如何觸發操作的呢?

 

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
				intent.addCategory(Intent.CATEGORY_OPENABLE);
				intent.setType("image/jpeg");
				startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE);


 

不同的手機調取的流程是不一樣的(我用的是魅族5),不管如何調用,當你選中你要裁剪的圖片(這裡還沒有進入裁剪頁面)就會在onActivityResult帶結果返回,這個方法中進入

 

case REQUEST_CODE_SELECT_IMAGE:
                	Log.i("Safly", "onActivityResult REQUEST_CODE_SELECT_IMAGE");
                    Intent intent = new Intent(this,CropImageActivity.class);
                    intent.setData(data.getData());
                    startActivityForResult(intent,REQUEST_CODE_IMAGE_CROP);
                    break;

 

 

我們做了什麼操作呢?我們緊接著又啟動了一個利用開源庫的裁剪功能的頁面,頁面是什麼樣子的呢? 我們看下布局文件的效果圖吧吧,我說下即可(一個返回,一個確定,還有一個CropImageView開源庫中的自定義FrameLayout)

\

 

那個小裁剪方塊可以拖動,可以擴展,待我們選取好需要裁剪的位置圖片後,點擊確定後

 

if(!isCompress){
                    Log.d(TAG,"start compress bitmap...");
                    byte[] bitmaps = compressBitmap(cropImageView.getCroppedImage());
                    if(bitmaps != null){
                        Intent data = new Intent();
                        data.putExtra(CROPBYTE,bitmaps);
                        setResult(0, data);
                        this.finish();
                    }
                    isCompress = false;
                }

我們在cropImageView.getCroppedImage()獲取裁剪得到的bitmap對象,然後判斷圖片的大小,在判斷是否進行壓縮,然後setResult(0, data);返回即可,在進行圓角控件設置

 

 

 case REQUEST_CODE_IMAGE_CROP:
                	Log.i("Safly", "onActivityResult REQUEST_CODE_IMAGE_CROP");
                    byte[] source = data.getByteArrayExtra(CropImageActivity.CROPBYTE);
                    icon = BitmapFactory.decodeByteArray(source,0,source.length);
                    contactIcon.setImageBitmap(icon);
\

 

缺點:1、某些機型,比如nexus選擇圖片時候,那個左側的圖片列表就不能對圖片進行選擇,不過n5對那個圖庫列表就可以進行裁剪

2、還有一個缺點就是裁剪時候,貌似只能裁剪到正方形

3、而且裁剪展現的頁面背後需要裁剪的圖像,在某些機型不會去覆蓋圖片的全部,意思就是圖片有些部分不能被裁剪到

PS一下:如果你能夠了解龐大的源碼,這些應該都可以解決的,

\

 

########################################代碼區#########################################

自己圓角控件attr屬性

 

    
        
 
        
 
        
 
        
 
            
 
            
 
        
    


 

activity_main.xml

 



    

        
    


activity_cropimage_layout.xml

 

 




    

    

    
    

    


MainActivity

 

 

package com.example.cropimageview;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {

	RoundImageView contactIcon;
	private static final int REQUEST_CODE_SELECT_IMAGE = 0x01;
	private static final int REQUEST_CODE_IMAGE_CROP = 0x02;
	  private Bitmap icon;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		contactIcon = (RoundImageView) findViewById(R.id.contactIcon);

		contactIcon.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
				intent.addCategory(Intent.CATEGORY_OPENABLE);
				intent.setType("image/jpeg");
				startActivityForResult(intent, REQUEST_CODE_SELECT_IMAGE);
			}
		});

	}

	

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(data != null){
            switch (requestCode){
                case REQUEST_CODE_SELECT_IMAGE:
                	Log.i("Safly", "onActivityResult REQUEST_CODE_SELECT_IMAGE");
                    Intent intent = new Intent(this,CropImageActivity.class);
                    intent.setData(data.getData());
                    startActivityForResult(intent,REQUEST_CODE_IMAGE_CROP);
                    break;
                case REQUEST_CODE_IMAGE_CROP:
                	Log.i("Safly", "onActivityResult REQUEST_CODE_IMAGE_CROP");
                    byte[] source = data.getByteArrayExtra(CropImageActivity.CROPBYTE);
                    icon = BitmapFactory.decodeByteArray(source,0,source.length);
                    contactIcon.setImageBitmap(icon);
                    break;
            }
        }
    }
}

CropImageActivity

 

 

package com.example.cropimageview;

import java.io.ByteArrayOutputStream;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.example.cropimageview.utils.CropImageView;

/**
 * Created by dandy on 2016/6/22.
 */
public class CropImageActivity extends Activity implements View.OnClickListener{

    private static final String TAG = "CropImageActivity";
    private CropImageView cropImageView;
    public static final String CROPBYTE = "crop_bytes";

    private boolean isCompress = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cropimage_layout);
        cropImageView = (CropImageView)findViewById(R.id.cropImageView);
        cropImageView.setImageUriAsync(getIntent().getData());


        findViewById(R.id.dirformCrop).setOnClickListener(this);
        findViewById(R.id.image_back).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.image_back:
                this.finish();
                break;
            case R.id.dirformCrop:
                if(!isCompress){
                    Log.d(TAG,"start compress bitmap...");
                    byte[] bitmaps = compressBitmap(cropImageView.getCroppedImage());
                    if(bitmaps != null){
                        Intent data = new Intent();
                        data.putExtra(CROPBYTE,bitmaps);
                        setResult(0, data);
                        this.finish();
                    }
                    isCompress = false;
                }
                break;
        }
    }

    private byte[] compressBitmap(Bitmap source){
        isCompress = true;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int options = 100;
        byte[] bytes = null;
        do{
            baos.reset();
            options -=10;
            source.compress(Bitmap.CompressFormat.JPEG, options <= 0 ? 0 : options, baos);
            if(options == 0 && baos.toByteArray().length / 1024 >= 30){
                Toast.makeText(this,"圖片裁剪過大,請調整大小",Toast.LENGTH_SHORT).show();
                bytes = null;
                break;
            }
        }while ((bytes = baos.toByteArray()).length / 1024 >= 30);
        return bytes;
//        return baos.toByteArray();
//        return BitmapFactory.decodeByteArray(baos.toByteArray(),0,baos.toByteArray().length);
    }
}

RoundImageView

 

 

package com.example.cropimageview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.ImageView;

public class RoundImageView extends ImageView{

    private static final String TAG = RoundImageView.class.getSimpleName();

    /**
     * 外部邊框的寬和顏色
     */
    private static final int DEFAULT_OUTER_BORDER_WIDTH = 0;
    private static final int DEFAULT_OUTER_BORDER_COLOR = Color.TRANSPARENT;
    private int outerWidth = DEFAULT_OUTER_BORDER_WIDTH;
    private int outerColor = DEFAULT_OUTER_BORDER_COLOR;

    private static final int COLORDRAWABLE_DIMENSION = 1;

    /**
     * 顯示圖片的類型
     */
    private static final int TYPE_CIRCLE = 0;
    private static final int TYPE_ROUND = 1;
    private int showType = TYPE_CIRCLE;

    /**
     * 圓角大小的默認值
     */
    private static final int DEFAULT_CORNER_ANGLE = 10;

    /**
     * 圓角實際大小值
     */
    private int mCornerAngle = 0;

    /**
     * 圓形圖片時候半徑大小
     */
    private int mCircleRadius = 0;

    /**
     * 繪圖畫筆paint
     */
    private Paint mBitmapPaint = null;
    private Paint mOuterPaint = null;


    /**
     * 3X3縮小放大矩陣
     */
    private Matrix mMatrix = null;

    /**
     * 渲染圖像,為繪制圖形著色
     */
    private BitmapShader mBitmapShader = null;

    /**
     * 大小
     */
    private int mCircleViewWidth = 0;
    private RectF mDrawableRectF = null;
    private RectF mOuterRectF = null;

    public RoundImageView(Context context) {
        this(context, null);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs);
    }

    /**
     * 初始化操作
     */
    private void init(AttributeSet attrs){

        TypedArray ta = getContext().obtainStyledAttributes(attrs,R.styleable.RoundImageView);

        showType = ta.getInt(R.styleable.RoundImageView_show_type, TYPE_CIRCLE);
        mCornerAngle = ta.getDimensionPixelSize(R.styleable.RoundImageView_corner_angle, dp2px());
        outerWidth = ta.getDimensionPixelSize(R.styleable.RoundImageView_outer_border_width, DEFAULT_OUTER_BORDER_WIDTH);
        outerColor = ta.getColor(R.styleable.RoundImageView_outer_border_color, DEFAULT_OUTER_BORDER_COLOR);

        ta.recycle();

        mMatrix = new Matrix();

        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);

        mOuterPaint = new Paint();
        mOuterPaint.setStyle(Paint.Style.STROKE);
        mOuterPaint.setAntiAlias(true);
        mOuterPaint.setColor(outerColor);
        mOuterPaint.setStrokeWidth(outerWidth);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /**
         * 測量的時候,如果獲取的類型是圓形的,則強制把view的寬高設為相同大小,以小的為標准
         */
        if(showType == TYPE_CIRCLE){
            mCircleViewWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
            mCircleRadius = mCircleViewWidth / 2 - outerWidth / 2;
            setMeasuredDimension(mCircleViewWidth, mCircleViewWidth);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        /**
         * 圓角圖片的范圍
         */
        if(showType == TYPE_ROUND){
            mOuterRectF = new RectF(0,0,getWidth(),getHeight());
            mDrawableRectF = new RectF(outerWidth,outerWidth,getWidth()-outerWidth,getHeight()-outerWidth);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if(drawable == null){
            drawable = getBackground();
        }
        if(drawable == null){
            Log.e(TAG, "[null] drawable is null.");
            return;
        }
        setShader(getBitmapFromDrawable(drawable));
        switch (showType) {
            case TYPE_CIRCLE:
                canvas.drawCircle(getWidth()/2, getHeight()/2, mCircleRadius, mBitmapPaint);
                canvas.drawCircle(getWidth()/2, getHeight()/2, mCircleRadius, mOuterPaint);
                break;

            case TYPE_ROUND:
                canvas.drawRoundRect(mDrawableRectF, mCornerAngle, mCornerAngle, mBitmapPaint);
                canvas.drawRoundRect(mOuterRectF, mCornerAngle, mCornerAngle, mOuterPaint);
                break;
        }
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        if(bm == null){
            bm = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.apply_virtual_number_photo);
        }
        super.setImageBitmap(bm);
    }

    /**
     * 初始化BitmapShader
     */
    private void setShader(Bitmap mBitmap){

        if(mBitmap == null){
            Log.i(TAG, "[null] mBitmap is null.");
            return;
        }

        if(mBitmapShader != null){
            mBitmapShader = null;
        }

        /**
         * 將mBitmap作為著色器,也就是在指定的區域內繪制mBitmap
         */
        mBitmapShader = new BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP);

        /**
         * 縮放比例
         */
        float scale = 1.0f;
        switch (showType) {
            case TYPE_CIRCLE:
                /**
                 * 拿圖片的寬高最小值做縮放比例
                 */
                scale = mCircleViewWidth * 1.0F / Math.min(mBitmap.getWidth(), mBitmap.getHeight());
                break;
            case TYPE_ROUND:
                /**
                 * 如果圖片的寬高與view的寬高不匹配,縮放的寬高一定要大於view的寬高才能填充完整view,所以要取較大值
                 */
                scale = Math.max(getWidth() * 1.0f /mBitmap.getWidth() , getHeight() * 1.0f / mBitmap.getHeight() );
                break;
        }

        /**
         * 變換矩陣設置縮放大小
         */
        mMatrix.setScale(scale,scale);

        /**
         * 設置變換矩陣
         */
        mBitmapShader.setLocalMatrix(mMatrix);

        /**
         * 設置著色器
         */
        mBitmapPaint.setShader(mBitmapShader);
    }

    /**
     * 從drawable中獲取bitmap
     */
    private Bitmap getBitmapFromDrawable(Drawable drawable){
        if(drawable == null){
            return null;
        }
        if(drawable instanceof BitmapDrawable){
            return ((BitmapDrawable)drawable).getBitmap();
        }

        try {
            Bitmap bitmap = null;
            if(drawable instanceof ColorDrawable){
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, Bitmap.Config.ARGB_8888);
            }else{
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);
            }
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根據手機獲取合適的像素大小
     */
    private int dp2px(){
        return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_ANGLE,
                getResources().getDisplayMetrics());
    }
}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved