AndroidClipSquare安卓實現方形頭像裁剪

來源:互聯網
上載者:User

標籤:des   android   blog   http   io   ar   os   使用   sp   

安卓實現方形頭像裁剪

實現思路,介面可見地區為2層View

最頂層的View是顯示層,主要繪製半透明邊框地區和白色裁剪地區,代碼比較容易。

第二層繼承ImageView,使用ImageView的Matrix實現顯示部分圖片,及挪動,放大縮小等操作。

比較複雜的地方在於多指操作對ImageView的影響,詳見代碼:

ClipSquareImageView.java

package com.h3c.androidclipsquare;import android.annotation.TargetApi;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.os.Build;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewTreeObserver;import android.widget.ImageView;/** * Created by H3c on 12/13/14. */public class ClipSquareImageView extends ImageView implements View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {    private static final int BORDERDISTANCE = ClipSquareView.BORDERDISTANCE;    public static final float DEFAULT_MAX_SCALE = 4.0f;    public static final float DEFAULT_MID_SCALE = 2.0f;    public static final float DEFAULT_MIN_SCALE = 1.0f;    private float minScale = DEFAULT_MIN_SCALE;    private float midScale = DEFAULT_MID_SCALE;    private float maxScale = DEFAULT_MAX_SCALE;    private MultiGestureDetector multiGestureDetector;    private boolean isIniting;// 正在初始化    private Matrix defaultMatrix = new Matrix();// 初始化的圖片矩陣,控製圖片撐滿螢幕及顯示地區    private Matrix dragMatrix = new Matrix();// 拖拽放大過程中動態矩陣    private Matrix finalMatrix = new Matrix();// 最終顯示的矩陣    private final RectF displayRect = new RectF();// 圖片的真實大小    private final float[] matrixValues = new float[9];    private int borderlength;    public ClipSquareImageView(Context context, AttributeSet attrs) {        super(context, attrs);        super.setScaleType(ScaleType.MATRIX);        setOnTouchListener(this);        multiGestureDetector = new MultiGestureDetector(context);    }    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        getViewTreeObserver().addOnGlobalLayoutListener(this);    }    @SuppressWarnings("deprecation")    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        getViewTreeObserver().removeGlobalOnLayoutListener(this);    }    @Override    public void onGlobalLayout() {        if(isIniting) {            return;        }        // 調整視圖位置        initBmpPosition();    }    /**     * 初始化圖片位置     */    private void initBmpPosition() {        isIniting = true;        super.setScaleType(ScaleType.MATRIX);        Drawable drawable = getDrawable();        if(drawable == null) {            return;        }        final float viewWidth = getWidth();        final float viewHeight = getHeight();        final int drawableWidth = drawable.getIntrinsicWidth();        final int drawableHeight = drawable.getIntrinsicHeight();        if(viewWidth < viewHeight) {            borderlength = (int) (viewWidth - 2 * BORDERDISTANCE);        } else {            borderlength = (int) (viewHeight - 2 * BORDERDISTANCE);        }        float screenScale = 1f;        // 小於螢幕的圖片會被撐滿螢幕        if(drawableWidth <= drawableHeight) {// 豎圖片            screenScale = (float) borderlength / drawableWidth;        } else {// 橫圖片            screenScale = (float) borderlength / drawableHeight;        }        defaultMatrix.setScale(screenScale, screenScale);        if(drawableWidth <= drawableHeight) {// 豎圖片            float heightOffset = (viewHeight - drawableHeight * screenScale) / 2.0f;            if(viewWidth <= viewHeight) {// 豎照片豎螢幕                defaultMatrix.postTranslate(BORDERDISTANCE, heightOffset);            } else {// 豎照片橫螢幕                defaultMatrix.postTranslate((viewWidth - borderlength) / 2.0f, heightOffset);            }        } else {            float widthOffset = (viewWidth - drawableWidth * screenScale) / 2.0f;            if(viewWidth <= viewHeight) {// 橫照片,豎螢幕                defaultMatrix.postTranslate(widthOffset, (viewHeight - borderlength) / 2.0f);            } else {// 橫照片,橫螢幕                defaultMatrix.postTranslate(widthOffset, BORDERDISTANCE);            }        }        resetMatrix();    }    /**     * Resets the Matrix back to FIT_CENTER, and then displays it.s     */    private void resetMatrix() {        if(dragMatrix == null) {            return;        }        dragMatrix.reset();        setImageMatrix(getDisplayMatrix());    }    private Matrix getDisplayMatrix() {        finalMatrix.set(defaultMatrix);        finalMatrix.postConcat(dragMatrix);        return finalMatrix;    }    @Override    public boolean onTouch(View view, MotionEvent motionEvent) {        return multiGestureDetector.onTouchEvent(motionEvent);    }    private class MultiGestureDetector extends GestureDetector.SimpleOnGestureListener implements            ScaleGestureDetector.OnScaleGestureListener {        private final ScaleGestureDetector scaleGestureDetector;        private final GestureDetector gestureDetector;        private final float scaledTouchSlop;        private VelocityTracker velocityTracker;        private boolean isDragging;        private float lastTouchX;        private float lastTouchY;        private float lastPointerCount;// 上一次是幾個手指事件        public MultiGestureDetector(Context context) {            scaleGestureDetector = new ScaleGestureDetector(context, this);            gestureDetector = new GestureDetector(context, this);            gestureDetector.setOnDoubleTapListener(this);            final ViewConfiguration configuration = ViewConfiguration.get(context);            scaledTouchSlop = configuration.getScaledTouchSlop();        }        @Override        public boolean onScale(ScaleGestureDetector scaleGestureDetector) {            float scale = getScale();            float scaleFactor = scaleGestureDetector.getScaleFactor();            if(getDrawable() != null && ((scale < maxScale && scaleFactor > 1.0f) || (scale > minScale && scaleFactor < 1.0f))){                if(scaleFactor * scale < minScale){                    scaleFactor = minScale / scale;                }                if(scaleFactor * scale > maxScale){                    scaleFactor = maxScale / scale;                }                dragMatrix.postScale(scaleFactor, scaleFactor, getWidth() / 2, getHeight() / 2);                checkAndDisplayMatrix();            }            return true;        }        @Override        public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {            return true;        }        @Override        public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {}        public boolean onTouchEvent(MotionEvent event) {            if (gestureDetector.onTouchEvent(event)) {                return true;            }            scaleGestureDetector.onTouchEvent(event);            /*             * Get the center x, y of all the pointers             */            float x = 0, y = 0;            final int pointerCount = event.getPointerCount();            for (int i = 0; i < pointerCount; i++) {                x += event.getX(i);                y += event.getY(i);            }            x = x / pointerCount;            y = y / pointerCount;            /*             * If the pointer count has changed cancel the drag             */            if (pointerCount != lastPointerCount) {                isDragging = false;                if (velocityTracker != null) {                    velocityTracker.clear();                }                lastTouchX = x;                lastTouchY = y;                lastPointerCount = pointerCount;            }            switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                    if (velocityTracker == null) {                        velocityTracker = VelocityTracker.obtain();                    } else {                        velocityTracker.clear();                    }                    velocityTracker.addMovement(event);                    lastTouchX = x;                    lastTouchY = y;                    isDragging = false;                    break;                case MotionEvent.ACTION_UP:                case MotionEvent.ACTION_CANCEL:                    lastPointerCount = 0;                    if (velocityTracker != null) {                        velocityTracker.recycle();                        velocityTracker = null;                    }                    break;                case MotionEvent.ACTION_MOVE: {                    final float dx = x - lastTouchX, dy = y - lastTouchY;                    if (isDragging == false) {                        // Use Pythagoras to see if drag length is larger than                        // touch slop                        isDragging = Math.sqrt((dx * dx) + (dy * dy)) >= scaledTouchSlop;                    }                    if (isDragging) {                        if (getDrawable() != null) {                            dragMatrix.postTranslate(dx, dy);                            checkAndDisplayMatrix();                        }                        lastTouchX = x;                        lastTouchY = y;                        if (velocityTracker != null) {                            velocityTracker.addMovement(event);                        }                    }                    break;                }            }            return true;        }        @Override        public boolean onDoubleTap(MotionEvent event) {            try {                float scale = getScale();                float x = getWidth() / 2;                float y = getHeight() / 2;                if (scale < midScale) {                    post(new AnimatedZoomRunnable(scale, midScale, x, y));                } else if ((scale >= midScale) && (scale < maxScale)) {                    post(new AnimatedZoomRunnable(scale, maxScale, x, y));                } else {// 雙擊縮小小於最小值                    post(new AnimatedZoomRunnable(scale, minScale, x, y));                }            } catch (Exception e) {                // Can sometimes happen when getX() and getY() is called            }            return true;        }    }    private class AnimatedZoomRunnable implements Runnable {        // These are 'postScale' values, means they're compounded each iteration        static final float ANIMATION_SCALE_PER_ITERATION_IN = 1.07f;        static final float ANIMATION_SCALE_PER_ITERATION_OUT = 0.93f;        private final float focalX, focalY;        private final float targetZoom;        private final float deltaScale;        public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,                                    final float focalX, final float focalY) {            this.targetZoom = targetZoom;            this.focalX = focalX;            this.focalY = focalY;            if (currentZoom < targetZoom) {                deltaScale = ANIMATION_SCALE_PER_ITERATION_IN;            } else {                deltaScale = ANIMATION_SCALE_PER_ITERATION_OUT;            }        }        @Override        public void run() {            dragMatrix.postScale(deltaScale, deltaScale, focalX, focalY);            checkAndDisplayMatrix();            final float currentScale = getScale();            if (((deltaScale > 1f) && (currentScale < targetZoom))                    || ((deltaScale < 1f) && (targetZoom < currentScale))) {                // We haven't hit our target scale yet, so post ourselves                // again                postOnAnimation(ClipSquareImageView.this, this);            } else {                // We've scaled past our target zoom, so calculate the                // necessary scale so we're back at target zoom                final float delta = targetZoom / currentScale;                dragMatrix.postScale(delta, delta, focalX, focalY);                checkAndDisplayMatrix();            }        }    }    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)    private void postOnAnimation(View view, Runnable runnable) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {            view.postOnAnimation(runnable);        } else {            view.postDelayed(runnable, 16);        }    }    /**     * Returns the current scale value     *     * @return float - current scale value     */    public final float getScale() {        dragMatrix.getValues(matrixValues);        return matrixValues[Matrix.MSCALE_X];    }    /**     * Helper method that simply checks the Matrix, and then displays the result     */    private void checkAndDisplayMatrix() {        checkMatrixBounds();        setImageMatrix(getDisplayMatrix());    }    private void checkMatrixBounds() {        final RectF rect = getDisplayRect(getDisplayMatrix());        if (null == rect) {            return;        }        float deltaX = 0, deltaY = 0;        final float viewWidth = getWidth();        final float viewHeight = getHeight();        // 判斷移動或縮放後,圖片顯示是否超出裁剪框邊界        final float heightBorder = (viewHeight - borderlength) / 2;        final float weightBorder = (viewWidth - borderlength) / 2;        if(rect.top > heightBorder){            deltaY = heightBorder - rect.top;        }        if(rect.bottom < (viewHeight - heightBorder)){            deltaY = viewHeight - heightBorder - rect.bottom;        }        if(rect.left > weightBorder){            deltaX = weightBorder - rect.left;        }        if(rect.right < viewWidth - weightBorder){            deltaX = viewWidth - weightBorder - rect.right;        }        // Finally actually translate the matrix        dragMatrix.postTranslate(deltaX, deltaY);    }    /**     * 擷取圖片相對Matrix的距離     *     * @param matrix     *            - Matrix to map Drawable against     * @return RectF - Displayed Rectangle     */    private RectF getDisplayRect(Matrix matrix) {        Drawable d = getDrawable();        if (null != d) {            displayRect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());            matrix.mapRect(displayRect);            return displayRect;        }        return null;    }    /**     * 剪下圖片,返回剪下後的bitmap對象     *     * @return     */    public Bitmap clip(){        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bitmap);        draw(canvas);        return Bitmap.createBitmap(bitmap, (getWidth() - borderlength) / 2, (getHeight() - borderlength) / 2, borderlength, borderlength);    }}


代碼下載:https://github.com/h3clikejava/AndroidClipSquare

AndroidClipSquare安卓實現方形頭像裁剪

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.