編輯:關於Android編程
以前寫過2篇關於相冊選取、裁剪的demo,今天我們來學習下github上一款開源的相冊裁剪開源庫
開源庫地址 https://github.com/ArthurHub/Android-Image-Cropper
首先我先說下這個開源庫需要添加的東東

上面截圖中CropImage可以不用,我代碼中用的自己的圓角代碼
上面是string幾個string 字體(我直接就從作者的開源代碼中直接拿過來的)Rotate counter clockwise Rotate Crop Select source
還有attrs.xml中需要的屬性
今天我們就寫一個小例子,來學習下,能夠將代碼跑起來,就ok了
首先看我代碼中的主布局文件,很簡單,只有一個圓角控件,點擊它以後,就掉系統的相冊應用
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;
}
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
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;
}
}
}
}
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);
}
}
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());
}
}
我的Android進階之旅------)關於使用CSDN-markdown編輯器來編寫博客
關於使用MarkDown編輯器的原因 其實前段時間就支持使用MarkDown編輯器來寫博客了,只是由於當時接觸過MarkDown,所以之前的博客都是使用默認的HTML編輯
Android拋物線下載動畫制作過程
下載動畫經常出現在下載需求多的app中,比如游戲下載平台,應用市場……先看看效果圖:實現private void startAnim() { //以bitmap創建
Android bluetooth介紹(三): 藍牙掃描(scan)設備分析
關鍵詞:藍牙blueZ A2DP、SINK、sink_connect、sink_disconnect、sink_suspend、sink_resume、sink_is_
Android5.0 v7擴展包之RecyclerView
RecylerView簡介 The RecyclerView widget is a more advanced and flexible version of List