仿微信头像剪切

来源:互联网 发布:Java开发dwg批量转jpg 编辑:程序博客网 时间:2024/05/16 17:36

来个动图:
这里写图片描述
裁剪效果其实就是图片在底部,上层一个视图重叠在上面,这里参考的是洪洋大神的仿微信头像篇,文章说的相当清楚了,我只是简洁的删改一点,看裁剪这个页面:

这里写图片描述
两个View重叠,就有了这个效果。看看底部View实现思路:底部View其实就是个ImageView,可以缩放,支持手势,直接贴代码吧

/** * 缩放图片的View * <p> * <p> * Created by dong.he on 2016/9/3. * <p> * blog:http://blog.csdn.net/hedong_77 */public class ClipZoomImageView extends ImageView implements        OnScaleGestureListener, OnTouchListener,        ViewTreeObserver.OnGlobalLayoutListener {    public static float SCALE_MAX = 4.0f;    private static float SCALE_MID = 2.0f;    /**     * 初始化时的缩放比例     */    private float initScale = 1.0f;    private boolean once = true;    /**     * 用于存放矩阵     */    private final float[] matrixValues = new float[9];    /**     * 缩放的手势检验     */    private ScaleGestureDetector mScaleGestureDetector = null;    private final Matrix mScaleMatrix = new Matrix();    /**     * 用于双击     */    private GestureDetector mGestureDetector;    private boolean isAutoScale;    private int mTouchSlop;    private float mLastX;    private float mLastY;    private boolean isCanDrag;    private int lastPointerCount;    /**     * 水平方向与View的边距     */    private int mHorizontalPadding;    public ClipZoomImageView(Context context) {        this(context, null);    }    public ClipZoomImageView(Context context, AttributeSet attrs) {        super(context, attrs);        setScaleType(ScaleType.MATRIX);        mGestureDetector = new GestureDetector(context,                new SimpleOnGestureListener() {                    @Override                    public boolean onDoubleTap(MotionEvent e) {                        if (isAutoScale == true)                            return true;                        float x = e.getX();                        float y = e.getY();                        if (getScale() < SCALE_MID) {                            ClipZoomImageView.this.postDelayed(                                    new AutoScaleRunnable(SCALE_MID, x, y), 16);                            isAutoScale = true;                        } else {                            ClipZoomImageView.this.postDelayed(                                    new AutoScaleRunnable(initScale, x, y), 16);                            isAutoScale = true;                        }                        return true;                    }                });        mScaleGestureDetector = new ScaleGestureDetector(context, this);        this.setOnTouchListener(this);    }    /**     * 自动缩放的任务     */    private class AutoScaleRunnable implements Runnable {        static final float BIGGER = 1.07f;        static final float SMALLER = 0.93f;        private float mTargetScale;        private float tmpScale;        private float x;        private float y;        /**         * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小         *         * @param targetScale         */        public AutoScaleRunnable(float targetScale, float x, float y) {            this.mTargetScale = targetScale;            this.x = x;            this.y = y;            if (getScale() < mTargetScale) {                tmpScale = BIGGER;            } else {                tmpScale = SMALLER;            }        }        @Override        public void run() {            // 进行缩放            mScaleMatrix.postScale(tmpScale, tmpScale, x, y);            checkBorder();            setImageMatrix(mScaleMatrix);            final float currentScale = getScale();            // 如果值在合法范围内,继续缩放            if (((tmpScale > 1f) && (currentScale < mTargetScale))                    || ((tmpScale < 1f) && (mTargetScale < currentScale))) {                ClipZoomImageView.this.postDelayed(this, 16);            } else            // 设置为目标的缩放比例            {                final float deltaScale = mTargetScale / currentScale;                mScaleMatrix.postScale(deltaScale, deltaScale, x, y);                checkBorder();                setImageMatrix(mScaleMatrix);                isAutoScale = false;            }        }    }    @Override    public boolean onScale(ScaleGestureDetector detector) {        float scale = getScale();        float scaleFactor = detector.getScaleFactor();        if (getDrawable() == null)            return true;        /**         * 缩放的范围控制         */        if ((scale < SCALE_MAX && scaleFactor > 1.0f)                || (scale > initScale && scaleFactor < 1.0f)) {            /**             * 最大值最小值判断             */            if (scaleFactor * scale < initScale) {                scaleFactor = initScale / scale;            }            if (scaleFactor * scale > SCALE_MAX) {                scaleFactor = SCALE_MAX / scale;            }            /**             * 设置缩放比例             */            mScaleMatrix.postScale(scaleFactor, scaleFactor,                    detector.getFocusX(), detector.getFocusY());            checkBorder();            setImageMatrix(mScaleMatrix);        }        return true;    }    /**     * 根据当前图片的Matrix获得图片的范围     *     * @return     */    private RectF getMatrixRectF() {        Matrix matrix = mScaleMatrix;        RectF rect = new RectF();        Drawable d = getDrawable();        if (null != d) {            rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());            matrix.mapRect(rect);        }        return rect;    }    @Override    public boolean onScaleBegin(ScaleGestureDetector detector) {        return true;    }    @Override    public void onScaleEnd(ScaleGestureDetector detector) {    }    @Override    public boolean onTouch(View v, MotionEvent event) {        if (mGestureDetector.onTouchEvent(event))            return true;        mScaleGestureDetector.onTouchEvent(event);        float x = 0, y = 0;        // 拿到触摸点的个数        final int pointerCount = event.getPointerCount();        // 得到多个触摸点的x与y均�?        for (int i = 0; i < pointerCount; i++) {            x += event.getX(i);            y += event.getY(i);        }        x = x / pointerCount;        y = y / pointerCount;        /**         * 每当触摸点发生变化时,重置mLasX , mLastY         */        if (pointerCount != lastPointerCount) {            isCanDrag = false;            mLastX = x;            mLastY = y;        }        lastPointerCount = pointerCount;        switch (event.getAction()) {            case MotionEvent.ACTION_MOVE:                float dx = x - mLastX;                float dy = y - mLastY;                if (!isCanDrag) {                    isCanDrag = isCanDrag(dx, dy);                }                if (isCanDrag) {                    if (getDrawable() != null) {                        RectF rectF = getMatrixRectF();                        // 如果宽度小于屏幕宽度,则禁止左右移动                        if (rectF.width() <= getWidth() - mHorizontalPadding * 2) {                            dx = 0;                        }                        // 如果高度小雨屏幕高度,则禁止上下移动                        if (rectF.height() <= getHeight() - getHVerticalPadding()                                * 2) {                            dy = 0;                        }                        mScaleMatrix.postTranslate(dx, dy);                        checkBorder();                        setImageMatrix(mScaleMatrix);                    }                }                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                lastPointerCount = 0;                break;        }        return true;    }    /**     * 获得当前的缩放比例     *     * @return     */    public final float getScale() {        mScaleMatrix.getValues(matrixValues);        return matrixValues[Matrix.MSCALE_X];    }    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        getViewTreeObserver().addOnGlobalLayoutListener(this);    }    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        getViewTreeObserver().removeGlobalOnLayoutListener(this);    }    /**     * 垂直方向与View的边距     */    // private int getHVerticalPadding();    @Override    public void onGlobalLayout() {        if (once) {            Drawable d = getDrawable();            if (d == null)                return;            int width = getWidth();            int height = getHeight();            // 拿到图片的宽和高            int drawableW = d.getIntrinsicWidth();            int drawableH = d.getIntrinsicHeight();            float scale = 1.0f;            int frameSize = getWidth() - mHorizontalPadding * 2;            // 大图            if (drawableW > frameSize && drawableH < frameSize) {                scale = 1.0f * frameSize / drawableH;            } else if (drawableH > frameSize && drawableW < frameSize) {                scale = 1.0f * frameSize / drawableW;            } else if (drawableW > frameSize && drawableH > frameSize) {                float scaleW = frameSize * 1.0f / drawableW;                float scaleH = frameSize * 1.0f / drawableH;                scale = Math.max(scaleW, scaleH);            }            // 太小的图片放大处理            if (drawableW < frameSize && drawableH > frameSize) {                scale = 1.0f * frameSize / drawableW;            } else if (drawableH < frameSize && drawableW > frameSize) {                scale = 1.0f * frameSize / drawableH;            } else if (drawableW < frameSize && drawableH < frameSize) {                float scaleW = 1.0f * frameSize / drawableW;                float scaleH = 1.0f * frameSize / drawableH;                scale = Math.max(scaleW, scaleH);            }            initScale = scale;            SCALE_MID = initScale * 2;            SCALE_MAX = initScale * 4;            mScaleMatrix.postTranslate((width - drawableW) / 2,                    (height - drawableH) / 2);            mScaleMatrix.postScale(scale, scale, getWidth() / 2,                    getHeight() / 2);            // 图片移动至屏幕中�?            setImageMatrix(mScaleMatrix);            once = false;        }    }    /**     * 剪切图片,返回剪切后的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, mHorizontalPadding,                getHVerticalPadding(), getWidth() - 2 * mHorizontalPadding,                getWidth() - 2 * mHorizontalPadding);    }    /**     * 边界线     */    private void checkBorder() {        RectF rect = getMatrixRectF();        float deltaX = 0;        float deltaY = 0;        int width = getWidth();        int height = getHeight();          // 如果宽或高大于屏幕,则控制范围; 这里是因为精度丢失会产生问题,但是误差一般很小,所以我们直接加了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 * getHVerticalPadding()) {            if (rect.top > getHVerticalPadding()) {                deltaY = -rect.top + getHVerticalPadding();            }            if (rect.bottom < height - getHVerticalPadding()) {                deltaY = height - getHVerticalPadding() - rect.bottom;            }        }        mScaleMatrix.postTranslate(deltaX, deltaY);    }    /**     * 是否是拖动行为     *     * @param dx     * @param dy     * @return     */    private boolean isCanDrag(float dx, float dy) {        return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;    }    public void setHorizontalPadding(int mHorizontalPadding) {        this.mHorizontalPadding = mHorizontalPadding;    }    private int getHVerticalPadding() {        return (getHeight() - (getWidth() - 2 * mHorizontalPadding)) / 2;    }}

注释很详细了。上层的View 是ClipImageBorderView,就是画边框而已,看看:
这里写图片描述
这里面有一个对外公开的方法,可以自动设置边距。
裁剪完成之后直接保存图片就Ok了。裁剪工作在ClipImageActivity里面做,后面源码。
为了考虑6.0的权限问题,demo里面也加入了权限适配,看一下MainActivity的源码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {    private Button takePhoto;    private Button selectImg;    private ImageView headImg;    private final int START_ALBUM_REQUESTCODE = 1;    private final int CAMERA_WITH_DATA = 2;    private final int CROP_RESULT_CODE = 3;    public static String TMP_PATH = "my.jpg";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        headImg = (ImageView) findViewById(R.id.iv_head);        takePhoto = (Button) findViewById(R.id.btn_take);        selectImg = (Button) findViewById(R.id.btn_select);        takePhoto.setOnClickListener(this);        selectImg.setOnClickListener(this);        permissionAlertDialog = new AlertDialog.Builder(getApplicationContext())                .setTitle(R.string.permission_request)                .setCancelable(false)                .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        PermissionUtil.goSetting(getApplicationContext());                        System.exit(0);                    }                })                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        System.exit(0);                    }                })                .create();    }    private void takePhoto() {        // 拍照        if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA)) {            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(                    Environment.getExternalStorageDirectory(), TMP_PATH)));            startActivityForResult(intent, CAMERA_WITH_DATA);        } else {            EasyPermissions.requestPermissions(this, getString(R.string.rationale_camera),                    PermissionUtil.PERMISSION_CAMERA_REQ, Manifest.permission.CAMERA);        }    }    // 从相册选择    private void selectImgByAlbum() {        Intent intent = new Intent(Intent.ACTION_PICK, null);        intent.setDataAndType(                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");        startActivityForResult(intent, START_ALBUM_REQUESTCODE);    }    // 裁剪图片的Activity    private void startCropImageActivity(String path) {        ClipImageActivity.startActivity(this, path, CROP_RESULT_CODE);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (resultCode == RESULT_OK) {            switch (requestCode) {                case CROP_RESULT_CODE:                    //最终路径(裁剪后的路径)                    final String path = data.getStringExtra(ClipImageActivity.RESULT_PATH);                    runOnUiThread(new Runnable() {                        @Override                        public void run() {                            Glide.with(MainActivity.this).load(path).asBitmap().into(headImg);                        }                    });                    break;                case START_ALBUM_REQUESTCODE:                    //返回裁剪                    if (data != null) {                        startCropImageActivity(Utils.getFilePath(this,data.getData()));                    } else {                        Toast.makeText(this, R.string.toast_cannot_retrieve_selected_image, Toast.LENGTH_SHORT).show();                    }                    break;                case CAMERA_WITH_DATA:                    // 照相机程序返回的,再次调用图片剪辑程序去修剪图片                    startCropImageActivity(Environment.getExternalStorageDirectory()                            + "/" + TMP_PATH);                    break;                default:                    break;            }        }    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_take:                takePhoto();                break;            case R.id.btn_select:                selectImgByAlbum();                break;        }    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        if (requestCode == PermissionUtil.PERMISSION_WRITE_EXTERNAL_STORAGE_REQ) {            if (grantResults.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {                showPermissionWarning(getString(R.string.permission_storage_warning));            }        }        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        // Forward results to EasyPermissions        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);    }    @Override    protected void onResume() {        super.onResume();//        if (!permissionAlertDialog.isShowing()) {        if (PermissionUtil.checkPermission(this, PermissionUtil.PERMISSION_WRITE_EXTERNAL_STORAGE, PermissionUtil.PERMISSION_WRITE_EXTERNAL_STORAGE_REQ)) {        }//        }    }    private AlertDialog permissionAlertDialog;    private void showPermissionWarning(String message) {        permissionAlertDialog.setMessage(message);        permissionAlertDialog.show();    }    @Override    public void onPermissionsGranted(int requestCode, List<String> perms) {    }    @Override    public void onPermissionsDenied(int requestCode, List<String> perms) {        if (requestCode == PermissionUtil.PERMISSION_CAMERA_REQ) {            EasyPermissions.checkDeniedPermissionsNeverAskAgain(this,                    getString(R.string.permission_camera_warning),                    R.string.setting, R.string.cancel, perms);        }    }}

注释清晰,源码下载:http://download.csdn.net/detail/hedong_77/9740640

2 0
原创粉丝点击