由于项目的需要,我们需要三种裁剪框,矩形裁剪框相信大家都不陌生,矩形的比较简单,思路:例如:正方形的裁剪框,我们只需要设置画笔的颜色为半透明的,然后绘制上下左右四个矩形即可组成一个正方形,那么圆形的怎么画呢?如果是同样的思路,那么我们就需要画两个不规则的图形,来组成圆,关键的地方就是那个半圆弧怎么画?我想到了用path,下面大家看一下效果:

正方形:

PictureSelector自定义裁剪界面 自定义裁剪形状_图形


圆形:

PictureSelector自定义裁剪界面 自定义裁剪形状_圆形_02


带角标的矩形:

PictureSelector自定义裁剪界面 自定义裁剪形状_path_03


下面看实现代码:

/**
     * 绘制裁剪框
     *
     * @param canvas
     */
    private void drawShape(Canvas canvas) {

        //矩形的画笔
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getResources().getColor(R.color.capture_view_bg));
        paint.setAntiAlias(true);

        //裁剪框白线的画笔
        Paint lPaint = new Paint();
        lPaint.setStyle(Paint.Style.FILL);
        lPaint.setColor(Color.WHITE);
        lPaint.setStrokeWidth(1);
        lPaint.setAntiAlias(true);

        //裁剪框角标的画笔
        Paint llPaint=new Paint();
        llPaint.setStyle(Paint.Style.FILL);
        llPaint.setColor(Color.WHITE);
        llPaint.setStrokeWidth(5);
        llPaint.setAntiAlias(true);


        //画圆的画笔

        Paint rPaint= new Paint();
        rPaint.setStyle(Paint.Style.STROKE);
        rPaint.setColor(Color.WHITE);
        rPaint.setStrokeWidth(5);
        rPaint.setAntiAlias(true);



        switch (shape) {

            case Rect:

                eage = width * 4 / 5;//设定裁剪框的变成是屏幕宽度的五分之四

                top = (height - eage) / 2;//绘制的正方形的顶部距离view顶端的距离

                bottom = eage + top;//绘制的正方形的底部距离view顶端的距离


                canvas.drawRect(0, 0, width, top, paint);//上矩形
                canvas.drawRect(0, top, width / 10, bottom, paint);//左矩形
                canvas.drawRect(width * 9 / 10, top, width, bottom, paint);//右矩形
                canvas.drawRect(0, bottom, width, height, paint);//下矩形


                canvas.drawLine(width / 10, top, width * 9 / 10, top, lPaint);//上白线
                canvas.drawLine(width / 10, top, width / 10, bottom, lPaint);//左白线
                canvas.drawLine(width * 9 / 10, top, width * 9 / 10, bottom, lPaint);//右白线
                canvas.drawLine(width / 10, bottom, width * 9 / 10, bottom, lPaint);//下白线


                break;

            case Circle:

                eage = width * 4 / 5;//设定裁剪框的变成是屏幕宽度的五分之四

                top = (height - eage) / 2;//绘制的正方形的顶部距离view顶端的距离

                bottom = eage + top;//绘制的正方形的底部距离view顶端的距离

                Path LPath=new Path();
                LPath.lineTo(width / 2, 0);
                LPath.lineTo(width / 2, top);
                LPath.cubicTo(-width / 30, top, -width / 30, bottom, width / 2, bottom);//三阶贝塞尔曲线
                LPath.lineTo(width / 2, height);
                LPath.lineTo(0, height);
                LPath.close();

                Path RPath=new Path();
                RPath.moveTo(width,0);
                RPath.lineTo(width / 2, 0);
                RPath.lineTo(width / 2, top);
                RPath.cubicTo(width * 31 / 30, top, width * 31 / 30, bottom, width / 2, bottom);
                RPath.lineTo(width / 2, height);
                RPath.lineTo(width, height);
                RPath.close();


                canvas.drawPath(LPath, paint);
                canvas.drawPath(RPath,paint);
                canvas.drawCircle(width/2,height/2,eage/2+2,rPaint);


                break;


            case ScreenRect:


                rectTop = (height - width / 2) / 2;//裁剪矩形上边缘距离view上方的距离
                rectBottom=rectTop + width / 2;//裁剪矩形底部边缘距离上方的距离

                rectCorner=width/16;

                //画矩形
                canvas.drawRect(0, 0, width, rectTop, paint);//上矩形
                canvas.drawRect(0, rectBottom, width, height, paint);//下矩形

                //画线

                canvas.drawLine(0,rectTop,width,rectTop,lPaint);//上边线
                canvas.drawLine(0,rectTop,0,rectBottom,lPaint);//左边线
                canvas.drawLine(width,rectTop,width,rectBottom,lPaint);//右边线
                canvas.drawLine(0,rectBottom,width,rectBottom,lPaint);//下边线


                //画8个小角标


                canvas.drawLine(0,rectTop+1,rectCorner,rectTop+1,llPaint);//左上横角标
                canvas.drawLine(1,rectTop,1,rectTop+rectCorner,llPaint);//左上竖角标
                canvas.drawLine(width-rectCorner,rectTop+1,width,rectTop+1,llPaint);//右上横角标
                canvas.drawLine(width-1,rectTop,width-1,rectCorner+rectTop,llPaint);//右上竖角标
                canvas.drawLine(0,rectBottom-1,rectCorner,rectBottom-1,llPaint);//左下横角标
                canvas.drawLine(1,rectBottom,1,rectBottom-rectCorner,llPaint);//左下竖角标
                canvas.drawLine(width,rectBottom-1,width-rectCorner,rectBottom-1,llPaint);//右下横角标
                canvas.drawLine(width-1,rectBottom,width-1,rectBottom-rectCorner,llPaint);//右下竖角标







                break;


            default:

                break;


        }

    }

如果对path不是很理解的:这里有一篇文章写的超级赞:
path绘制
代码我都做了比较详细的注释,相信比较好理解,不懂的可以留言哦!
其实裁剪框,弄好了,就剩下裁剪了呗,裁剪比较简单,这里我是采用手机屏幕截图的方式实现的只贴代码,有兴趣的童鞋可以看一下,其实这个截图方式不是很满意,有好的方式的欢迎大家讨论:
首先一个工具类:

**
 * 获得屏幕相关的辅助类
 */
public class ScreenUtils {
    private ScreenUtils() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    /**
     * 获得屏幕宽度
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 获得屏幕高度
     *
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }

    /**
     * 获得状态栏的高度
     *
     * @param context
     * @return
     */
    public static int getStatusHeight(Context context) {

        int statusHeight = -1;
        try {
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            int height = Integer.parseInt(clazz.getField("status_bar_height")
                    .get(object).toString());
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }

    /**
     * 获取当前屏幕截图,包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
        view.destroyDrawingCache();
        return bp;

    }

    /**
     * 获取当前屏幕截图,不包含状态栏
     *
     * @param activity
     * @return
     */
    public static Bitmap snapShotWithoutStatusBar(Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bmp = view.getDrawingCache();
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        int width = getScreenWidth(activity);
        int height = getScreenHeight(activity);
        Bitmap bp = null;
        bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
                - statusBarHeight);
        view.destroyDrawingCache();
        return bp;

    }



}

下面的具体的实现:使用到Bitmap的creatBitmap:

/**
     * 获取裁剪图片
     *
     * @param activity
     * @return
     */
    public static Bitmap takeScreenShot(Activity activity) {

        //去掉标题栏,actionbar 的高度
        Bitmap b = Bitmap.createBitmap(ScreenUtils.snapShotWithStatusBar(activity), 0,
                ScreenUtils.getScreenHeight(activity) - height-viewHeight, width,
                height);

        switch (CaptureView.shape) {

            case Rect:

                //偏移一个像素,避免截取白线
                b = Bitmap.createBitmap(b, width / 10 + 1, top + 1, eage - 2, eage - 2);


                break;

            case Circle:



                //偏移一个像素,避免截取白线
//                b = toRoundBitmap(Bitmap.createBitmap(b, width / 10 + 1, top + 1, eage - 2, eage - 2));

                //偏移一个像素,避免截取白线
                b = Bitmap.createBitmap(b, width / 10 + 1, top + 1, eage - 2, eage - 2);



                break;


            case ScreenRect:

                //偏移一个像素,避免截取白线
                b = Bitmap.createBitmap(b, 6, rectTop+6, width-12, width/2 - 12);

                break;


            default:

                break;


        }

        return comp(b);
    }

关于压缩图片的方式这个比较简单,从网站找了一段代码:

public static Bitmap comp(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        if (baos.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//这里压缩50%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 800f;//这里设置高度为800f
        float ww = 480f;//这里设置宽度为480f
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;//设置缩放比例
        //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);

        return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
    }

    private static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) {    //循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片

        return bitmap;
    }

就这样吧。~