Android 仿微信, QQ 裁剪

Android 仿微信, QQ 裁剪

前言

在平時開發中,經常需要實現這樣的功能,拍照 - 裁剪,相冊 - 裁剪。當然,系統也有裁剪的功能,但是由於機型,系統兼容性等問題,在實際開發當中,我們通常會自己進行實現。今天,就讓我們一起來看看怎樣實現。

這篇博客實現的功能主要有仿微信,QQ 上傳圖像裁剪功能,包括拍照,從相冊選取。裁剪框的樣式有圓形,正方形,九宮格。

主要講解的功能點

  1. 使用說明
  2. 整體的實現思路
  3. 裁剪框的實現
  4. 圖片縮放的實現,包括放大,縮小,移動,裁剪等

我們先來看看我們實現的效果圖

拍照裁剪的
[圖片上傳失敗...(image-1f22da-1557492128625)]

相冊裁剪的
[圖片上傳失敗...(image-dbb3d5-1557492128625)]


使用說明

有兩種調用方式

第一種

第一種,使用普通的 startActivityForResult 進行調用,並重寫 onActivityResult 方法,在裏面根據 requestCode 進行處理

ClipImageActivity.goToClipActivity(this, uri);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    switch (requestCode) {
        case REQ_CLIP_AVATAR:  //剪切圖片返回
            if (resultCode == RESULT_OK) {
                final Uri uri = intent.getData();
                if (uri == null) {
                    return;
                }
                String cropImagePath = FileUtil.getRealFilePathFromUri(getApplicationContext(), uri);
                
                
    ----
                
}

第二種

第二種調用 ClipImageActivity.goToClipActivity 方法,結果以 callBack 回調的方式返回回來,這種看起來比較直觀點,個人也比較喜歡這種方法。它的實現原理是通過空白的 fragment 處理實現的,有興趣的可以看我這一篇博客 Android Fragment 的妙用 - 優雅地申請權限和處理 onActivityResult

ClipImageActivity.goToClipActivity(this, uri, new ActivityResultHelper.Callback() {
    @Override
    public void onActivityResult(int resultCode, Intent data) {
        
    }
});


整體實現思路

從上面的效果圖我們可以看到,裁剪功能主要包括兩大塊

  1. 裁剪框
  2. 圖片的縮放,移動,裁剪等

因此,爲了方便日後的修改,我們將裁剪框的功能單獨提取出來,圖片縮放功能提出出來。即裁剪框單獨一個 View。

下面,讓我們一起來看看裁剪框功能的實現。


裁剪框功能的實現

裁剪框主要有兩層,第一層,裁剪框的實現(包括圓形,長方形,九宮格形狀),第二層,在裁剪區域上面蓋上一層蒙層。

蒙層

蒙層的實現我們是通過 Xfermode 實現的

xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);


//通過Xfermode的DST_OUT來產生中間的透明裁剪區域,一定要另起一個Layer(層)
canvas.saveLayer(0, 0, this.getWidth(), this.getHeight(), null, Canvas.ALL_SAVE_FLAG);

//設置背景
canvas.drawColor(Color.parseColor("#a8000000"));
paint.setXfermode(xfermode);

圓形裁剪框的實現

繪製圓形裁剪框很容易實現,主要確定圓心和半徑即可

//中間的透明的圓
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, paint);
//白色的圓邊框
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, borderPaint);

正方形裁剪框的實現

繪製長方形的話主要要確定四個點的座標 left ,top, right, botom。
很簡單

left = mHorizontalPadding;
top = this.getHeight() / 2 - clipWidth / 2;
right =   this.getWidth() - mHorizontalPadding;
botom = this.getHeight() / 2 + clipWidth / 2;
//繪製中間白色的矩形蒙層
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
        this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, paint);
//繪製白色的矩形邊框
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
        this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, borderPaint);

九宮格的

九宮格的繪製稍微繁瑣一點,分三個步驟

  1. 繪製長方形邊框
  2. 繪製九宮格引導線
  3. 繪製裁剪邊框的是個直角

我們來看一下繪製九宮格引導線的

  • 繪製豎直方向兩條線
  • 繪製水平方向兩條線
private void drawGuidelines(@NonNull Canvas canvas, Rect clipRect) {

    final float left = clipRect.left;
    final float top = clipRect.top;
    final float right = clipRect.right;
    final float bottom = clipRect.bottom;

    final float oneThirdCropWidth = (right - left) / 3;

    final float x1 = left + oneThirdCropWidth;
    //引導線豎直方向第一條線
    canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint);
    final float x2 = right - oneThirdCropWidth;
    //引導線豎直方向第二條線
    canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint);

    final float oneThirdCropHeight = (bottom - top) / 3;

    final float y1 = top + oneThirdCropHeight;
    //引導線水平方向第一條線
    canvas.drawLine(left, y1, right, y1, mGuidelinePaint);
    final float y2 = bottom - oneThirdCropHeight;
    //引導線水平方向第二條線
    can

繪製四個直角的

private void drawCorners(@NonNull Canvas canvas, Rect clipRect) {

    final float left = clipRect.left;
    final float top = clipRect.top;
    final float right = clipRect.right;
    final float bottom = clipRect.bottom;

    //簡單的數學計算
    final float lateralOffset = (mCornerThickness - mBorderThickness) / 2f;
    final float startOffset = mCornerThickness - (mBorderThickness / 2f);

    //左上角左面的短線
    canvas.drawLine(left - lateralOffset, top - startOffset, left - lateralOffset, top + mCornerLength, mCornerPaint);
    //左上角上面的短線
    canvas.drawLine(left - startOffset, top - lateralOffset, left + mCornerLength, top - lateralOffset, mCornerPaint);

    //右上角右面的短線
    canvas.drawLine(right + lateralOffset, top - startOffset, right + lateralOffset, top + mCornerLength, mCornerPaint);
    //右上角上面的短線
    canvas.drawLine(right + startOffset, top - lateralOffset, right - mCornerLength, top - lateralOffset, mCornerPaint);

    //左下角左面的短線
    canvas.drawLine(left - lateralOffset, bottom + startOffset, left - lateralOffset, bottom - mCornerLength, mCornerPaint);
    //左下角底部的短線
    canvas.drawLine(left - startOffset, bottom + lateralOffset, left + mCornerLength, bottom + lateralOffset, mCornerPaint);

    //右下角左面的短線
    canvas.drawLine(right + lateralOffset, bottom + startOffset, right + lateralOffset, bottom - mCornerLength, mCornerPaint);
    //右下角底部的短線
    canvas.drawLine(right + startOffset, bottom + lateralOffset, right - mCornerLength, bottom + lateralOffset, mCornerPaint);
}


圖片裁剪框的實現到此講解完畢,更多細節請參考 ClipView


圖片的縮放,移動

實現原理簡述

這裏我們是通過 ClipViewLayout 實現的,它是 RelativeLayout 的子類,裏面含有 ImageView 和 ClipView(裁剪框)。我們通過監聽 ClipViewLayout 的 onTouchEvent 事件,設置 imageView 的圖片矩陣。

我們先來了解一下,主要有三種模式,NONE,DRAG, ZOOM。NONE 表示初始模式,DRAG 表示拖拽模式,ZOOM 表示縮放模式

private static final int NONE = 0;
//動作標誌:拖動
private static final int DRAG = 1;
//動作標誌:縮放
private static final int ZOOM = 2;

當我們多個手指按下的時候,加入兩個手指之間的距離超過 10,此時我們認爲進入 ZOOM 模式。DRAG 模式的話當我們手指按下的時候進入。NONE 模式,當我們手機擡起的時候,進入復位模式。

switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        Log.d(TAG, "onTouchEvent: ACTION_DOWN");
        mSavedMatrix.set(mMatrix);
        //設置開始點位置
        mStart.set(event.getX(), event.getY());
        mode = DRAG;
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        //開始放下時候兩手指間的距離
        mOldDist = spacing(event);
        if (mOldDist > 10f) {
            mSavedMatrix.set(mMatrix);
            midPoint(mMid, event);
            mode = ZOOM;
        }
        break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
        mode = NONE;
        break;


接下來我們一起來看一下,我們 action_move 的時候,我們是怎樣進行移動和縮放的。

移動的話相對比較簡單,首先它會計算出我們這一次 event 事件相對我們 action_down 時候 event 事件的偏移量 dx, dy。接着調用 mMatrix.postTranslate(dx, dy),進行矩陣的移動。最後,再檢測是否超出邊界。

case MotionEvent.ACTION_MOVE:
    Log.d(TAG, "onTouchEvent: mode =" + mode);
    if (mode == DRAG) { //拖動
        mMatrix.set(mSavedMatrix);
        float dx = event.getX() - mStart.x;
        float dy = event.getY() - mStart.y;

        mVerticalPadding = mClipView.getClipRect().top;
        mMatrix.postTranslate(dx, dy);
        //檢查邊界
        checkBorder();
    } 
    ---
    mImageView.setImageMatrix(mMatrix);

邊界檢測 主要是檢查縮放,移動後的圖片矩陣的 left, top,right, bottom 是否在圖片裁剪框之內,如果在的話,需要對圖片矩陣進行移動。確保邊界不在裁剪框之內。

/**
 * 邊界檢測
 */
private void checkBorder() {
    RectF rect = getMatrixRectF(mMatrix);
    float deltaX = 0;
    float deltaY = 0;
    int width = mImageView.getWidth();
    int height = mImageView.getHeight();
    // 如果寬或高大於屏幕,則控制範圍 ; 這裏的0.001是因爲精度丟失會產生問題,但是誤差一般很小,所以我們直接加了一個0.01
    if (rect.width() + 0.01 >= width - 2 * mHorizontalPadding) {
        // 圖片矩陣的最左邊 > 裁剪邊框的左邊
        if (rect.left > mHorizontalPadding) {
            deltaX = -rect.left + mHorizontalPadding;
        }
        // 圖片矩陣的最右邊 < 裁剪邊框的右邊
        if (rect.right < width - mHorizontalPadding) {
            deltaX = width - mHorizontalPadding - rect.right;
        }
    }
    if (rect.height() + 0.01 >= height - 2 * mVerticalPadding) {
        // 圖片矩陣的 top > 裁剪邊框的 top
        if (rect.top > mVerticalPadding) {
            deltaY = -rect.top + mVerticalPadding;
        }
        // 圖片矩陣的 bottom < 裁剪邊框的 bottom
        if (rect.bottom < height - mVerticalPadding) {
            deltaY = height - mVerticalPadding - rect.bottom;
        }
    }

    Log.i(TAG, "checkBorder: deltaX=" + deltaX + " deltaY = " + deltaY);

    mMatrix.postTranslate(deltaX, deltaY);
}

裁剪功能的實現

/**
 * 獲取剪切圖
 */
public Bitmap clip() {
    mImageView.setDrawingCacheEnabled(true);
    mImageView.buildDrawingCache();
    Rect rect = mClipView.getClipRect();
    Bitmap cropBitmap = null;
    Bitmap zoomedCropBitmap = null;
    try {
        cropBitmap = Bitmap.createBitmap(mImageView.getDrawingCache(), rect.left, rect.top, rect.width(), rect.height());
        // 對圖片進行壓縮,這裏因爲 mPreViewW 與寬高是相等的,所以壓縮比例是 1:1,可以根據需要自己調整
        zoomedCropBitmap = BitmapUtil.zoomBitmap(cropBitmap, mPreViewW, mPreViewW);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (cropBitmap != null) {
        cropBitmap.recycle();

[Android 仿微信, QQ 裁剪](https://blog.csdn.net/gdutxiaoxu/article/details/89576088)

## 前言

在平時開發中,經常需要實現這樣的功能,拍照 - 裁剪,相冊 - 裁剪。當然,系統也有裁剪的功能,但是由於機型,系統兼容性等問題,在實際開發當中,我們通常會自己進行實現。今天,就讓我們一起來看看怎樣實現。

這篇博客實現的功能主要有仿微信,QQ 上傳圖像裁剪功能,包括拍照,從相冊選取。裁剪框的樣式有圓形,正方形,九宮格。

主要講解的功能點
1. 使用說明
2. 整體的實現思路
3. 裁剪框的實現
4. 圖片縮放的實現,包括放大,縮小,移動,裁剪等

我們先來看看我們實現的效果圖

拍照裁剪的
![拍照裁剪的](https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/19_04/camera.gif)

相冊裁剪的
![相冊裁剪的](https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/19_04/album.gif)


---

## 使用說明

有兩種調用方式


### 第一種

第一種,使用普通的 startActivityForResult 進行調用,並重寫 onActivityResult 方法,在裏面根據 requestCode 進行處理

ClipImageActivity.goToClipActivity(this, uri);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case REQ_CLIP_AVATAR: //剪切圖片返回
if (resultCode == RESULT_OK) {
final Uri uri = intent.getData();
if (uri == null) {
return;
}
String cropImagePath = FileUtil.getRealFilePathFromUri(getApplicationContext(), uri);

----

}


### 第二種

第二種調用 ClipImageActivity.goToClipActivity 方法,結果以 callBack 回調的方式返回回來,這種看起來比較直觀點,個人也比較喜歡這種方法。它的實現原理是通過空白的 fragment 處理實現的,有興趣的可以看我這一篇博客 [Android Fragment 的妙用 - 優雅地申請權限和處理 onActivityResult](https://blog.csdn.net/gdutxiaoxu/article/details/86498647)

ClipImageActivity.goToClipActivity(this, uri, new ActivityResultHelper.Callback() {
@Override
public void onActivityResult(int resultCode, Intent data) {

}

});


---

## 整體實現思路

從上面的效果圖我們可以看到,裁剪功能主要包括兩大塊
1. 裁剪框
2. 圖片的縮放,移動,裁剪等

因此,爲了方便日後的修改,我們將裁剪框的功能單獨提取出來,圖片縮放功能提出出來。即裁剪框單獨一個 View。

下面,讓我們一起來看看裁剪框功能的實現。

---

## 裁剪框功能的實現

![](https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/19_04/20190425202444.png)

裁剪框主要有兩層,第一層,裁剪框的實現(包括圓形,長方形,九宮格形狀),第二層,在裁剪區域上面蓋上一層蒙層。

### 蒙層

蒙層的實現我們是通過 Xfermode 實現的

xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);

//通過Xfermode的DST_OUT來產生中間的透明裁剪區域,一定要另起一個Layer(層)
canvas.saveLayer(0, 0, this.getWidth(), this.getHeight(), null, Canvas.ALL_SAVE_FLAG);

//設置背景
canvas.drawColor(Color.parseColor("#a8000000"));
paint.setXfermode(xfermode);




### 圓形裁剪框的實現

繪製圓形裁剪框很容易實現,主要確定圓心和半徑即可



//中間的透明的圓
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, paint);
//白色的圓邊框
canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, borderPaint);


### 正方形裁剪框的實現

![](https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/19_04/20190425202353.png)

繪製長方形的話主要要確定四個點的座標 left ,top, right, botom。
很簡單


left = mHorizontalPadding;
top = this.getHeight() / 2 - clipWidth / 2;
right = this.getWidth() - mHorizontalPadding;
botom = this.getHeight() / 2 + clipWidth / 2;



//繪製中間白色的矩形蒙層
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, paint);
//繪製白色的矩形邊框
canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, borderPaint);


### 九宮格的

![](https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/19_04/20190425203737.png)

九宮格的繪製稍微繁瑣一點,分三個步驟
1. 繪製長方形邊框
2. 繪製九宮格引導線
3. 繪製裁剪邊框的是個直角


我們來看一下繪製九宮格引導線的
- 繪製豎直方向兩條線
- 繪製水平方向兩條線


```java
private void drawGuidelines(@NonNull Canvas canvas, Rect clipRect) {

    final float left = clipRect.left;
    final float top = clipRect.top;
    final float right = clipRect.right;
    final float bottom = clipRect.bottom;

    final float oneThirdCropWidth = (right - left) / 3;

    final float x1 = left + oneThirdCropWidth;
    //引導線豎直方向第一條線
    canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint);
    final float x2 = right - oneThirdCropWidth;
    //引導線豎直方向第二條線
    canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint);

    final float oneThirdCropHeight = (bottom - top) / 3;

    final float y1 = top + oneThirdCropHeight;
    //引導線水平方向第一條線
    canvas.drawLine(left, y1, right, y1, mGuidelinePaint);
    final float y2 = bottom - oneThirdCropHeight;
    //引導線水平方向第二條線
    can

繪製四個直角的

private void drawCorners(@NonNull Canvas canvas, Rect clipRect) {

    final float left = clipRect.left;
    final float top = clipRect.top;
    final float right = clipRect.right;
    final float bottom = clipRect.bottom;

    //簡單的數學計算
    final float lateralOffset = (mCornerThickness - mBorderThickness) / 2f;
    final float startOffset = mCornerThickness - (mBorderThickness / 2f);

    //左上角左面的短線
    canvas.drawLine(left - lateralOffset, top - startOffset, left - lateralOffset, top + mCornerLength, mCornerPaint);
    //左上角上面的短線
    canvas.drawLine(left - startOffset, top - lateralOffset, left + mCornerLength, top - lateralOffset, mCornerPaint);

    //右上角右面的短線
    canvas.drawLine(right + lateralOffset, top - startOffset, right + lateralOffset, top + mCornerLength, mCornerPaint);
    //右上角上面的短線
    canvas.drawLine(right + startOffset, top - lateralOffset, right - mCornerLength, top - lateralOffset, mCornerPaint);

    //左下角左面的短線
    canvas.drawLine(left - lateralOffset, bottom + startOffset, left - lateralOffset, bottom - mCornerLength, mCornerPaint);
    //左下角底部的短線
    canvas.drawLine(left - startOffset, bottom + lateralOffset, left + mCornerLength, bottom + lateralOffset, mCornerPaint);

    //右下角左面的短線
    canvas.drawLine(right + lateralOffset, bottom + startOffset, right + lateralOffset, bottom - mCornerLength, mCornerPaint);
    //右下角底部的短線
    canvas.drawLine(right + startOffset, bottom + lateralOffset, right - mCornerLength, bottom + lateralOffset, mCornerPaint);
}


圖片裁剪框的實現到此講解完畢,更多細節請參考 ClipView


圖片的縮放,移動

實現原理簡述

這裏我們是通過 ClipViewLayout 實現的,它是 RelativeLayout 的子類,裏面含有 ImageView 和 ClipView(裁剪框)。我們通過監聽 ClipViewLayout 的 onTouchEvent 事件,設置 imageView 的圖片矩陣。

我們先來了解一下,主要有三種模式,NONE,DRAG, ZOOM。NONE 表示初始模式,DRAG 表示拖拽模式,ZOOM 表示縮放模式

private static final int NONE = 0;
//動作標誌:拖動
private static final int DRAG = 1;
//動作標誌:縮放
private static final int ZOOM = 2;

當我們多個手指按下的時候,加入兩個手指之間的距離超過 10,此時我們認爲進入 ZOOM 模式。DRAG 模式的話當我們手指按下的時候進入。NONE 模式,當我們手機擡起的時候,進入復位模式。

switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        Log.d(TAG, "onTouchEvent: ACTION_DOWN");
        mSavedMatrix.set(mMatrix);
        //設置開始點位置
        mStart.set(event.getX(), event.getY());
        mode = DRAG;
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        //開始放下時候兩手指間的距離
        mOldDist = spacing(event);
        if (mOldDist > 10f) {
            mSavedMatrix.set(mMatrix);
            midPoint(mMid, event);
            mode = ZOOM;
        }
        break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
        mode = NONE;
        break;


接下來我們一起來看一下,我們 action_move 的時候,我們是怎樣進行移動和縮放的。

移動的話相對比較簡單,首先它會計算出我們這一次 event 事件相對我們 action_down 時候 event 事件的偏移量 dx, dy。接着調用 mMatrix.postTranslate(dx, dy),進行矩陣的移動。最後,再檢測是否超出邊界。

case MotionEvent.ACTION_MOVE:
    Log.d(TAG, "onTouchEvent: mode =" + mode);
    if (mode == DRAG) { //拖動
        mMatrix.set(mSavedMatrix);
        float dx = event.getX() - mStart.x;
        float dy = event.getY() - mStart.y;

        mVerticalPadding = mClipView.getClipRect().top;
        mMatrix.postTranslate(dx, dy);
        //檢查邊界
        checkBorder();
    } 
    ---
    mImageView.setImageMatrix(mMatrix);

邊界檢測 主要是檢查縮放,移動後的圖片矩陣的 left, top,right, bottom 是否在圖片裁剪框之內,如果在的話,需要對圖片矩陣進行移動。確保邊界不在裁剪框之內。

/**
 * 邊界檢測
 */
private void checkBorder() {
    RectF rect = getMatrixRectF(mMatrix);
    float deltaX = 0;
    float deltaY = 0;
    int width = mImageView.getWidth();
    int height = mImageView.getHeight();
    // 如果寬或高大於屏幕,則控制範圍 ; 這裏的0.001是因爲精度丟失會產生問題,但是誤差一般很小,所以我們直接加了一個0.01
    if (rect.width() + 0.01 >= width - 2 * mHorizontalPadding) {
        // 圖片矩陣的最左邊 > 裁剪邊框的左邊
        if (rect.left > mHorizontalPadding) {
            deltaX = -rect.left + mHorizontalPadding;
        }
        // 圖片矩陣的最右邊 < 裁剪邊框的右邊
        if (rect.right < width - mHorizontalPadding) {
            deltaX = width - mHorizontalPadding - rect.right;
        }
    }
    if (rect.height() + 0.01 >= height - 2 * mVerticalPadding) {
        // 圖片矩陣的 top > 裁剪邊框的 top
        if (rect.top > mVerticalPadding) {
            deltaY = -rect.top + mVerticalPadding;
        }
        // 圖片矩陣的 bottom < 裁剪邊框的 bottom
        if (rect.bottom < height - mVerticalPadding) {
            deltaY = height - mVerticalPadding - rect.bottom;
        }
    }

    Log.i(TAG, "checkBorder: deltaX=" + deltaX + " deltaY = " + deltaY);

    mMatrix.postTranslate(deltaX, deltaY);
}

裁剪功能的實現

/**
 * 獲取剪切圖
 */
public Bitmap clip() {
    mImageView.setDrawingCacheEnabled(true);
    mImageView.buildDrawingCache();
    Rect rect = mClipView.getClipRect();
    Bitmap cropBitmap = null;
    Bitmap zoomedCropBitmap = null;
    try {
        cropBitmap = Bitmap.createBitmap(mImageView.getDrawingCache(), rect.left, rect.top, rect.width(), rect.height());
        // 對圖片進行壓縮,這裏因爲 mPreViewW 與寬高是相等的,所以壓縮比例是 1:1,可以根據需要自己調整
        zoomedCropBitmap = BitmapUtil.zoomBitmap(cropBitmap, mPreViewW, mPreViewW);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (cropBitmap != null) {
        cropBitmap.recycle();
    }
    // 釋放資源
    mImageView.destroyDrawingCache();
    return zoomedCropBitmap;
}

題外話

這個 Demo 涉及到的 Android 技術點其實是蠻多的,可以說是麻雀雖小,五臟俱全。Android 7.0 圖片拍照適配,6.0 動態權限申請,Android 使用空白 fragment 處理 onActivityResult,動態權限申請,自定義 View,View 的事件分發機制等等。

這篇博客主要是介紹個人認爲比較重要的技術點,其他的可以自行取了解。最後,提供一下 demo 下載地址: https://github.com/gdutxiaoxu/clipimage

特別鳴謝

文中很多代碼參考了以下兩篇文章,在他們的基礎之上進行了修改。由於時間的關係,並沒有對裁剪框進行更多細節化的定製,比如圖片比例,自定義屬性的暴露等,有興趣的話可以自己進行添加

android-headimage-cliper

Android 高仿微信頭像截取 打造不一樣的自定義控件

github 源碼地址

clipimage

掃一掃,歡迎關注我的公衆號。如果你有好的文章,也歡迎你的投稿。

}
// 釋放資源
mImageView.destroyDrawingCache();
return zoomedCropBitmap;

}


---

## 題外話

這個 Demo 涉及到的 Android 技術點其實是蠻多的,可以說是麻雀雖小,五臟俱全。Android 7.0 圖片拍照適配,6.0 動態權限申請,Android 使用空白 fragment  處理  onActivityResult,動態權限申請,自定義 View,View 的事件分發機制等等。

這篇博客主要是介紹個人認爲比較重要的技術點,其他的可以自行取了解。最後,提供一下 demo 下載地址: https://github.com/gdutxiaoxu/clipimage


### 特別鳴謝

文中很多代碼參考了以下兩篇文章,在他們的基礎之上進行了修改。由於時間的關係,並沒有對裁剪框進行更多細節化的定製,比如圖片比例,自定義屬性的暴露等,有興趣的話可以自己進行添加

[android-headimage-cliper](https://github.com/wsy858/android-headimage-cliper)

[Android 高仿微信頭像截取 打造不一樣的自定義控件](https://blog.csdn.net/lmj623565791/article/details/39761281)

github 源碼地址

[clipimage](https://github.com/gdutxiaoxu/clipimage)


![Android 技術人](http://upload-images.jianshu.io/upload_images/2050203-291945dac11e97af.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**掃一掃,歡迎關注我的公衆號。如果你有好的文章,也歡迎你的投稿。**

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章