自定义控件-截屏当前界面


以下是在图片裁剪类的原型上修改过的:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.hmy.android.allforme.util.DimenUtil;

/**
 * Created by hmy 
 */
public class CropImageView extends View {
    protected Context mContext;
    private DimenUtil dimenUtil;

    // 在touch重要用到的点,
    private float mX_1 = 0;
    private float mY_1 = 0;
    // 当前状态
    private TouchStatus touchStatus = TouchStatus.STATUS_SINGLE;
    // 默认裁剪的宽高
    private int cropWidth = 0;
    private int cropHeight = 0;
    //手指触摸位置
    public TouchPosition touchPosition = TouchPosition.EDGE_NONE;

    protected Drawable mDrawable;//被裁剪对象
    protected FloatDrawable mFloatDrawable;//裁剪层

    protected Rect mDrawableSrc = new Rect();// 图片Rect变换时的Rect
    protected Rect mDrawableDst = new Rect();// 图片Rect
    protected Rect mDrawableFloat = new Rect();// 裁剪层的Rect

    private boolean isTouchInSquare = true;//当前触点是否在裁剪框内
    protected boolean isFrist = true;//
    protected float oriRationWH = 0;//
    private boolean isCropEnable = true;

    public void setCropEnable(boolean cropEnable) {
        this.isCropEnable = cropEnable;
    }

    /**
     * 手指触摸状态
     */
    public enum TouchStatus {
        STATUS_SINGLE,//单指触摸
        STATUS_MULTI_START,//多指触摸开始
        STATUS_MULTI_TOUCHING,//多指触摸中
    }

    /**
     * 手指触摸位置
     */
    public enum TouchPosition {
        EDGE_LT,//左上角
        EDGE_RT,//右上角
        EDGE_LB,//左下角
        EDGE_RB,//右下角
        EDGE_MOVE_IN,//裁剪框内部
        EDGE_MOVE_OUT,//裁剪框外部
        EDGE_NONE,//nothing
    }

    public CropImageView(Context context) {
        super(context);
        init(context);
    }

    public CropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public CropImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);

    }

    /**
     * 初始化
     *
     * @param context
     */
    private void init(Context context) {
        this.mContext = context;
        try {
            if (android.os.Build.VERSION.SDK_INT >= 11) {
                this.setLayerType(LAYER_TYPE_SOFTWARE, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.isFrist = true;
        mFloatDrawable = new FloatDrawable(context);
        dimenUtil = new DimenUtil(mContext);
        cropWidth = dimenUtil.getScreenWidth();
        cropHeight = dimenUtil.getScreenHeight();
    }

    /**
     * 设置被裁剪样本
     *
     * @param mDrawable
     * @param cropWidth
     * @param cropHeight
     */
    public void setDrawable(Drawable mDrawable, int cropWidth, int cropHeight) {
        this.cropWidth = cropWidth;
        this.cropHeight = cropHeight;

        this.mDrawable = mDrawable;
        invalidate();
    }

    /**
     * 设置被裁剪样本
     *
     * @param mDrawable
     */
    public void setDrawable(Drawable mDrawable) {
        this.mDrawable = mDrawable;
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getPointerCount() > 1) {
            switch (touchStatus) {
                case STATUS_SINGLE:
                    touchStatus = TouchStatus.STATUS_MULTI_START;
                    break;
                case STATUS_MULTI_START:
                    touchStatus = TouchStatus.STATUS_MULTI_TOUCHING;
                    break;
            }
        } else {
            switch (touchStatus) {
                case STATUS_MULTI_TOUCHING:
                case STATUS_MULTI_START:
                    mX_1 = event.getX();
                    mY_1 = event.getY();
                    break;
            }
            touchStatus = TouchStatus.STATUS_SINGLE;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mX_1 = event.getX();
                mY_1 = event.getY();
                touchPosition = getTouchPosition(mX_1, mY_1);
                isTouchInSquare = mDrawableFloat.contains((int) event.getX(),
                        (int) event.getY());
                break;

            case MotionEvent.ACTION_UP:
                checkBounds();
                break;

            case MotionEvent.ACTION_POINTER_UP:
                touchPosition = TouchPosition.EDGE_NONE;
                break;

            case MotionEvent.ACTION_MOVE:
                switch (touchStatus) {
                    case STATUS_MULTI_TOUCHING:
                        //多指触摸中...
                        break;
                    case STATUS_SINGLE:
                        int dx = (int) (event.getX() - mX_1);
                        int dy = (int) (event.getY() - mY_1);

                        mX_1 = event.getX();
                        mY_1 = event.getY();
                        // 根據得到的那一个角,并且变换Rect
                        if (!(dx == 0 && dy == 0)) {
                            switch (touchPosition) {
                                case EDGE_LT:
                                    mDrawableFloat.set(mDrawableFloat.left + dx,
                                            mDrawableFloat.top + dy, mDrawableFloat.right,
                                            mDrawableFloat.bottom);
                                    break;

                                case EDGE_RT:
                                    mDrawableFloat.set(mDrawableFloat.left,
                                            mDrawableFloat.top + dy, mDrawableFloat.right
                                                    + dx, mDrawableFloat.bottom);
                                    break;

                                case EDGE_LB:
                                    mDrawableFloat.set(mDrawableFloat.left + dx,
                                            mDrawableFloat.top, mDrawableFloat.right,
                                            mDrawableFloat.bottom + dy);
                                    break;

                                case EDGE_RB:
                                    mDrawableFloat.set(mDrawableFloat.left,
                                            mDrawableFloat.top, mDrawableFloat.right + dx,
                                            mDrawableFloat.bottom + dy);
                                    break;

                                case EDGE_MOVE_IN:
                                    if (isTouchInSquare) {
                                        mDrawableFloat.offset(dx, dy);
                                    }
                                    break;

                                case EDGE_MOVE_OUT:
                                    //这部分可以控制图片的缩放,位移
                                    break;
                            }
                            mDrawableFloat.sort();
                            invalidate();
                        }
                        break;
                }
                break;
        }
        return true;
    }

    /**
     * 根据初触摸点判断是触摸的Rect哪一个角
     */
    public TouchPosition getTouchPosition(float eventX, float eventY) {
        if (mFloatDrawable.getBounds().left <= eventX
                && eventX < (mFloatDrawable.getBounds().left + mFloatDrawable
                .getBorderWidth())
                && mFloatDrawable.getBounds().top <= eventY
                && eventY < (mFloatDrawable.getBounds().top + mFloatDrawable
                .getBorderHeight())) {
            return TouchPosition.EDGE_LT;
        } else if ((mFloatDrawable.getBounds().right - mFloatDrawable
                .getBorderWidth()) <= eventX
                && eventX < mFloatDrawable.getBounds().right
                && mFloatDrawable.getBounds().top <= eventY
                && eventY < (mFloatDrawable.getBounds().top + mFloatDrawable
                .getBorderHeight())) {
            return TouchPosition.EDGE_RT;
        } else if (mFloatDrawable.getBounds().left <= eventX
                && eventX < (mFloatDrawable.getBounds().left + mFloatDrawable
                .getBorderWidth())
                && (mFloatDrawable.getBounds().bottom - mFloatDrawable
                .getBorderHeight()) <= eventY
                && eventY < mFloatDrawable.getBounds().bottom) {
            return TouchPosition.EDGE_LB;
        } else if ((mFloatDrawable.getBounds().right - mFloatDrawable
                .getBorderWidth()) <= eventX
                && eventX < mFloatDrawable.getBounds().right
                && (mFloatDrawable.getBounds().bottom - mFloatDrawable
                .getBorderHeight()) <= eventY
                && eventY < mFloatDrawable.getBounds().bottom) {
            return TouchPosition.EDGE_RB;
        } else if (mFloatDrawable.getBounds().contains((int) eventX, (int) eventY)) {
            return TouchPosition.EDGE_MOVE_IN;
        }
        return TouchPosition.EDGE_MOVE_OUT;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //如果没有设置裁剪样本,则赋值一个空的图层
        if (mDrawable == null) {
            mDrawable = new BitmapDrawable(mContext.getResources(), getEmptyBitmap());
        }
        //设定 界限 规则
        initBounds();
        // 画图片
        mDrawable.draw(canvas);
        //画裁剪框
        drawCropUI(canvas);
    }

    /**
     * 绘制裁剪框样式
     *
     * @param canvas
     */
    private void drawCropUI(Canvas canvas) {
        if (!isCropEnable) {
            return;
        }
        canvas.save();
        // 在画布上画浮层FloatDrawable,Region.Op.DIFFERENCE是表示Rect交集的补集
        canvas.clipRect(mDrawableFloat, Region.Op.DIFFERENCE);
        // 在交集的补集上画上灰色用来区分
        canvas.drawColor(Color.parseColor("#a0000000"));
        canvas.restore();
        // 画浮层
        mFloatDrawable.draw(canvas);
    }

    /**
     * 初始化 界限 参数,在onDraw方法中调用;
     * isFirst的目的是下面对mDrawableSrc和mDrawableFloat只初始化一次;
     * 之后的变化是根据touch事件来变化的,而不是每次执行重新对mDrawableSrc和mDrawableFloat进行设置
     */
    protected void initBounds() {
        if (isFrist) {
            oriRationWH = ((float) mDrawable.getIntrinsicWidth())
                    / ((float) mDrawable.getIntrinsicHeight());

            final float scale = mContext.getResources().getDisplayMetrics().density;
            int w = Math.min(getWidth(), (int) (mDrawable.getIntrinsicWidth()
                    * scale + 0.5f));
            int h = (int) (w / oriRationWH);

            int left = (getWidth() - w) / 2;
            int top = (getHeight() - h) / 2;
            int right = left + w;
            int bottom = top + h;

            mDrawableSrc.set(left, top, right, bottom);
            mDrawableDst.set(mDrawableSrc);

            if (cropWidth > getWidth()) {
                cropWidth = getWidth();
                cropHeight = cropHeight * cropWidth / cropWidth;
            }

            if (cropHeight > getHeight()) {
                cropHeight = getHeight();
                cropWidth = cropWidth * cropHeight / cropHeight;
            }

            int floatLeft = (getWidth() - cropWidth) / 2;
            int floatTop = (getHeight() - cropHeight) / 2;
            mDrawableFloat.set(floatLeft, floatTop, floatLeft + cropWidth,
                    floatTop + cropHeight);
            isFrist = false;
        }

        mDrawable.setBounds(mDrawableDst);
        mFloatDrawable.setBounds(mDrawableFloat);
    }

    /**
     * 在up事件中调用了该方法,目的是检查是否把浮层拖出了屏幕
     */
    protected void checkBounds() {
        int newLeft = mDrawableFloat.left;
        int newTop = mDrawableFloat.top;

        boolean isChange = false;
        if (mDrawableFloat.left < getLeft()) {
            newLeft = getLeft();
            isChange = true;
        }

        if (mDrawableFloat.top < getTop()) {
            newTop = getTop();
            isChange = true;
        }

        if (mDrawableFloat.right > getRight()) {
            newLeft = getRight() - mDrawableFloat.width();
            isChange = true;
        }

        if (mDrawableFloat.bottom > getBottom()) {
            newTop = getBottom() - mDrawableFloat.height();
            isChange = true;
        }

        mDrawableFloat.offsetTo(newLeft, newTop);
        if (isChange) {
            invalidate();
        }
    }

    /**
     * 进行图片的裁剪,所谓的裁剪就是根据Drawable的新的坐标在画布上创建一张新的图片
     */
    public Bitmap getCropImage() {
        Bitmap result = null;
        if (!isCropEnable) {
            return result;
        }
        Bitmap tmpBitmap = getEmptyBitmap();
        Canvas canvas = new Canvas(tmpBitmap);
        mDrawable.draw(canvas);

        result = Bitmap.createBitmap(tmpBitmap, mDrawableFloat.left,
                mDrawableFloat.top, mDrawableFloat.width(),
                mDrawableFloat.height());

        recycle(tmpBitmap);
        return result;
    }

    private void recycle(Bitmap bitmap) {
        try {
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
                System.gc();
            }
        } catch (Exception var2) {
            var2.printStackTrace();
        }
    }

    private Bitmap getEmptyBitmap() {
        return Bitmap.createBitmap(dimenUtil.getScreenWidth(), dimenUtil.getScreenHeight(), Bitmap.Config.RGB_565);
    }
}


以上,类中用到的工具类:

import android.content.Context;
import android.view.View;

/**
 * Created by hmy 
 */
public class DimenUtil {
    private Context mContext;
    private float density = -1.0F;
    private int widthPixels = -1;
    private int heightPixels = -1;

    public DimenUtil(Context context) {
        this.mContext = context;
    }

    public float getDensity() {
        if (density <= 0.0F) {
            density = mContext.getResources().getDisplayMetrics().density;
        }

        return density;
    }

    public int dip2px(float dpValue) {
        return (int) (dpValue * getDensity() + 0.5F);
    }

    public int px2dip(float pxValue) {
        return (int) (pxValue / getDensity() + 0.5F);
    }

    public int getScreenWidth() {
        if (widthPixels <= 0) {
            widthPixels = mContext.getResources().getDisplayMetrics().widthPixels;
        }

        return widthPixels;
    }

    public int getScreenHeight() {
        if (heightPixels <= 0) {
            heightPixels = mContext.getResources().getDisplayMetrics().heightPixels;
        }

        return heightPixels;
    }
}
还需要把裁剪框封装到另一个控件中,使用的时候将下面的控件作为根布局,调用相关方法就可以截屏其包含的view:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;

/**
 * Created by hmy 
 */
public class ScreenShotView extends FrameLayout {
    private Context mContext;
    private CropImageView mCropIv;

    private int mWidth = 0;
    private int mHeight = 0;

    public ScreenShotView(Context context) {
        super(context);
        init(context);
    }

    public ScreenShotView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ScreenShotView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
        mCropIv = new CropImageView(mContext);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        checkChildView();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        this.mWidth = this.getWidth();
        this.mHeight = this.getHeight();
    }

    /**
     * 检查子view
     */
    private void checkChildView() {
        int count = this.getChildCount();
        if (count != 1) {
            throw new RuntimeException("ScreenShotView can only have one child view!");
        } else {
            this.addView(mCropIv);
            initScreenView();
        }
    }

    /**
     * 初始化截屏view
     */
    private void initScreenView() {
        final View screenView = this.getChildAt(0);
        screenView.buildDrawingCache();
        // 允许当前窗口保存缓存信息
        screenView.setDrawingCacheEnabled(true);
        //view加载完成时回调
        screenView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                try {
                    //获取bitmap
                    Bitmap bmp = Bitmap.createBitmap(screenView.getDrawingCache(), 0, 0, mWidth, mHeight);
                    // 销毁缓存信息
                    screenView.destroyDrawingCache();
                    mCropIv.setDrawable(new BitmapDrawable(mContext.getResources(), bmp));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 获取截取框内的图片
     *
     * @return
     */
    public Bitmap getCropImage() {
        return mCropIv.getCropImage();
    }

    public void setCropEnable(boolean enable) {
        mCropIv.setCropEnable(enable);
    }
}
使用方法:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.hmy.android.allforme.view.ScreenShotView
        android:id="@+id/main_crop"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@mipmap/bj" />
    </com.hmy.android.allforme.view.ScreenShotView>

    <ImageView
        android:id="@+id/main_iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignParentRight="true"
        android:background="#afff"
        android:src="@mipmap/groundoverlay" />
</RelativeLayout>

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import com.hmy.android.allforme.R;
import com.hmy.android.allforme.view.ScreenShotView;

public class MainActivity extends Activity {
    private ScreenShotView imageView;
    private ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ScreenShotView) findViewById(R.id.main_crop);
        iv = (ImageView) findViewById(R.id.main_iv);

        iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap mBitmap = imageView.getCropImage();
                iv.setImageBitmap(mBitmap);
            }
        });
    }
}

猜你喜欢

转载自blog.csdn.net/u014040795/article/details/52191688