編輯:關於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()); } }
關於使用MarkDown編輯器的原因 其實前段時間就支持使用MarkDown編輯器來寫博客了,只是由於當時接觸過MarkDown,所以之前的博客都是使用默認的HTML編輯
下載動畫經常出現在下載需求多的app中,比如游戲下載平台,應用市場……先看看效果圖:實現private void startAnim() { //以bitmap創建
關鍵詞:藍牙blueZ A2DP、SINK、sink_connect、sink_disconnect、sink_suspend、sink_resume、sink_is_
RecylerView簡介 The RecyclerView widget is a more advanced and flexible version of List