Android 仿qq上傳頭像(一),android
轉載請註明出處http://blog.csdn.net/u014163726/article/details/44994197
這麼長時間沒寫部落格感覺手都要生了啊,最近因為工作的關係來到了上海,目前還算穩定,所以抓緊時間寫篇部落格壓壓驚。
標題早已經看穿一切,這次我們來模仿一下qq上傳頭像的功能,先上一個未完成版的,銀魂第四季重開放上一張萌萌噠的圖片。
這還是要用到我們自訂View的知識,首先從相簿中擷取圖片的部分我就不詳細介紹了。
/** * 獲得圖片 */protected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == CHOOSE_BIG_PICTURE) {photoBitmap = null;photoViewBitmap = null;try {Uri originalUri = data.getData();int angle = getExifOrientation(getRealPathFromURI(originalUri));if (angle != 0) { // 如果照片出現了 旋轉 那麼 就更改旋轉度數Matrix matrix = new Matrix();matrix.postRotate(angle);photoBitmap = getBitmapFromUri(photoBitmap, originalUri);photoViewBitmap = Bitmap.createBitmap(photoBitmap, 0, 0,photoBitmap.getWidth(), photoBitmap.getHeight(),matrix, true);clipView.setBitmap(photoViewBitmap);} else {clipView.setBitmap(getBitmapFromUri(photoBitmap,originalUri));}photoBitmap.recycle();photoViewBitmap.recycle();} catch (Exception e) {System.out.println(e.getMessage());}}}
我當時用的是三星的Note3測試發現擷取的圖片會發生旋轉十分的坑爹。。所以我們還需要根據uri拿到路徑然後再判斷圖片是否旋轉。
/** * 根據Uri獲得bitmap * * @param bitmap * @param uri * @return */private Bitmap getBitmapFromUri(Bitmap bitmap, Uri uri) {try {bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);return bitmap;} catch (Exception e) {Log.d("TAG", e.getLocalizedMessage());return null;}}/** * 獲得系統相簿圖片 */private void getAlbum() {Intent intent = new Intent(Intent.ACTION_PICK);intent.setType("image/*");// 相片類型startActivityForResult(intent, CHOOSE_BIG_PICTURE);}/** * 旋轉圖片 * * @param filepath * @return */private int getExifOrientation(String filepath) {int degree = 0;ExifInterface exif = null;try {exif = new ExifInterface(filepath);} catch (IOException ex) {}if (exif != null) {int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);if (orientation != -1) {switch (orientation) {case ExifInterface.ORIENTATION_ROTATE_90:degree = 90;break;case ExifInterface.ORIENTATION_ROTATE_180:degree = 180;break;case ExifInterface.ORIENTATION_ROTATE_270:degree = 270;break;}}}return degree;}/** * 根據Uri拿到路徑 * * @param contentUri * @return */public String getRealPathFromURI(Uri contentUri) {String res = null;String[] proj = { MediaStore.Images.Media.DATA };Cursor cursor = getContentResolver().query(contentUri, proj, null,null, null);if (cursor.moveToFirst()) {int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);res = cursor.getString(column_index);}cursor.close();return res;}
拿到圖片之後就進入我們的自訂view環節啦。
public class ClipView extends View {/** * 畫筆 */private Paint paint;/** * 圖片 */private Bitmap mBitmap;/** * 畫布 */private Canvas mCanvas;/** * 蒙版 */private Bitmap bitmap;/** * 起點座標 */private int startX, startY;/** * 移動距離 */private int distanceX, distanceY;/** * 圖片座標 */private int widthX, heightY;int x = 0, y = 0;public ClipView(Context context) {super(context);init();// TODO Auto-generated constructor stub}public ClipView(Context context, AttributeSet attrs) {super(context, attrs);init();}public ClipView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}
我們預設把傳進來的圖片縮放至600,800這樣不會讓圖片過大也不會過小。
/** * 縮放圖片 * * @param bgimage * @param newWidth * @param newHeight * @return */private Bitmap zoomImage(Bitmap bgimage, double newWidth, double newHeight) {// 擷取這個圖片的寬和高float width = bgimage.getWidth();float height = bgimage.getHeight();// 建立操作圖片用的matrix對象Matrix matrix = new Matrix();// 計算寬高縮放率float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;// 縮放圖片動作matrix.postScale(scaleWidth, scaleHeight);Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,(int) height, matrix, true);return bitmap;}/** * 拿到圖片首先進行縮放 * * @param bitmap */public void setBitmap(Bitmap bitmap) {this.mBitmap = zoomImage(bitmap, 600, 800);startX = -(600 / 2);startY = -(800 / 2);widthX = startX;heightY = startY;postInvalidate();}
做到這一步的時候我們再來看看效果
可以看到我們光有了圖片還是遠遠不夠滴,我們還需要一個圓以及一個蒙版效果,那麼問題就來了,這個蒙版效果是怎麼做的呢,再上一張圖,圖片來自網路
看到這張圖我們要知道先繪製的是黃色的後繪製的是藍色的,那麼我們蒙版的效果要用哪種來實現呢。我選擇用DstOut,這種模式取得是非交集下層部分。理清了思路,接下來我們就繼續寫代碼吧。
private void init() {// 建立空白畫布bitmap = Bitmap.createBitmap(600, 800, Config.ARGB_8888);mCanvas = new Canvas(bitmap);paint = new Paint();paint.setStyle(Style.FILL);paint.setStrokeWidth(2);paint.setAntiAlias(true);}@Overrideprotected void onDraw(Canvas canvas) {canvas.translate(getWidth() / 2, getHeight() / 2);if (mBitmap != null) {restartCanvas();canvas.drawBitmap(mBitmap, widthX, heightY, null);mCanvas.drawCircle(-widthX, -heightY, 200, paint);canvas.drawBitmap(bitmap, widthX, heightY, null);}}
我們再onDraw中繪製了我們的背景圖片以及蒙版效果再加一個半徑為200的圓,接下來做的就是不斷的改變背景位置來完成移動的效果,每次移動之前要先clear掉上次的畫布。
private void restartCanvas() {// 清空上一次的繪圖狀態paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));mCanvas.drawPaint(paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));mCanvas.drawColor(getResources().getColor(R.color.bg));}
要記清楚DSTOUT的效果哦!
/** * 移動x位置 */private void getWidthX() {widthX = startX - distanceX;if (widthX > -200) {widthX = -200;distanceX = -100;} else if (widthX < -400) {widthX = -400;distanceX = 100;}}/** * 移動y位置 */private void getHeightY() {heightY = startY - distanceY;if (heightY > -200) {heightY = -200;distanceY = -100;} else if (heightY < -600) {heightY = -600;distanceY = 100;}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:x = (int) event.getX();y = (int) event.getY();break;case MotionEvent.ACTION_MOVE:distanceX = x - (int) (event.getX());distanceY = y - (int) (event.getY());getWidthX();getHeightY();break;case MotionEvent.ACTION_UP:startX = widthX;startY = heightY;break;default:break;}postInvalidate();return true;}
今天這部分的代碼就到這裡了,可以看到目前我們還欠缺的是隨手勢放大背景圖片,以及最後的剪下!這就留到下一次吧。。。
項目源碼