可移动缩放拖拽的ViewfinderView

这里写图片描述为了这个可以拖拽的扫描框,着实头痛了几天
主要借鉴文章:http://blog.csdn.net/farble/article/details/44235555
public final class ViewfinderView extends View {
private static final String TAG = “log”;
/**
* 刷新界面的时间
*/
private static final long ANIMATION_DELAY = 10L;
private static final int OPAQUE = 0xFF;

/**
 * 四个绿色边角对应的长度
 */
private int ScreenRate;

/**
 * 四个绿色边角对应的宽度
 */
private static final int CORNER_WIDTH = 10;
/**
 * 扫描框中的中间线的宽度
 */
private static final int MIDDLE_LINE_WIDTH = 6;

/**
 * 扫描框中的中间线的与扫描框左右的间隙
 */
private static final int MIDDLE_LINE_PADDING = 5;

/**
 * 中间那条线每次刷新移动的距离
 */
private static final int SPEEN_DISTANCE = 5;

/**
 * 手机的屏幕密度
 */
private static float density;
/**
 * 字体大小
 */
private static final int TEXT_SIZE = 16;
/**
 * 字体距离扫描框下面的距离
 */
private static final int TEXT_PADDING_TOP = 30;

/**
 * 画笔对象的引用
 */
private Paint paint;

/**
 * 中间滑动线的最顶端位置
 */
private int slideTop;

/**
 * 中间滑动线的最底端位置
 */
private int slideBottom;

/**
 * 将扫描的二维码拍下来,这里没有这个功能,暂时不考虑
 */
private Bitmap resultBitmap;
private final int maskColor;
private final int resultColor;

private final int resultPointColor;
private Collection<ResultPoint> possibleResultPoints;
private Collection<ResultPoint> lastPossibleResultPoints;

boolean isFirst;

//TODO start
private onLocationListener locationListener;/*listen to the Rect */
private onChangeLocationlistener changeLocationlistener;/*listening position changed */

private int MODE;
private static final int MODE_OUTSIDE = 0x000000aa;/*170*/
private static final int MODE_INSIDE = 0x000000bb;/*187*/
private static final int MODE_POINT = 0X000000cc;/*204*/
private static final int MODE_ILLEGAL = 0X000000dd;/*221*/

private static final int minWidth = 100;/*the minimum width of the rectangle*/
private static final int minHeight = 200;/*the minimum height of the rectangle*/

private static final int START_X = 200;
private static final int START_Y = 200;

private static final float EDGE_WIDTH = 1.8f;
private static final int ACCURACY = 15;/*touch accuracy*/

private int pointPosition;/*vertex of a rectangle*/

private int sX;/*start X location*/
private int sY;/*start Y location*/
private int eX;/*end X location*/
private int eY;/*end Y location*/

private int pressX;/*X coordinate values while finger press*/
private int pressY;/*Y coordinate values while finger press*/

private int memonyX;/*the last time the coordinate values of X*/
private int memonyY;/*the last time the coordinate values of Y*/

private int coverWidth = 600;/*width of selection box*/
private int coverHeight = 720;/*height of selection box*/

private Paint mPaint;
private Paint mPaintLine;
private Bitmap mBitmapCover;
private Bitmap mBitmapRectBlack;
private PorterDuffXfermode xfermode;/*paint mode*/

//TODO end
public ViewfinderView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
    density = context.getResources().getDisplayMetrics().density;
    //将像素转换成dp
    ScreenRate = (int) (20 * density);


    paint = new Paint();
    Resources resources = getResources();
    maskColor = resources.getColor(R.color.viewfinder_mask);
    resultColor = resources.getColor(R.color.result_view);

    resultPointColor = resources.getColor(R.color.possible_result_points);
    possibleResultPoints = new HashSet<ResultPoint>(5);
}

@SuppressWarnings("deprecation")
private void init() {
   /* sX = START_X;
    sY = START_Y;*/
    WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    int width = manager.getDefaultDisplay().getWidth();
    int height = manager.getDefaultDisplay().getHeight();
    mBitmapCover = makeBitmap(width, height, 0x5A000000, 0, 0);
    mBitmapRectBlack = makeBitmap(coverWidth, coverHeight, 0xff000000, coverWidth, coverHeight);
    sX = width / 2 - coverWidth / 2;
    sY = height / 2 - coverHeight / 2;
    eX = sX + coverWidth;
    eY = sY + coverHeight;
    pressX = 0;
    pressY = 0;

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

    mPaint = new Paint();
    mPaint.setAntiAlias(true);

    mPaintLine = new Paint();
    mPaintLine.setColor(Color.WHITE);
    mPaintLine.setStrokeWidth(2.0f);
}

/*生成bitmap*/
private Bitmap makeBitmap(int mwidth, int mheight, int resource, int staX, int staY) {
    Bitmap bm = Bitmap.createBitmap(mwidth, mheight, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);

    p.setColor(resource);
    c.drawRect(staX, staY, mwidth, mheight, p);
    return bm;
}

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    //请求父控件不拦截触摸事件
    getParent().requestDisallowInterceptTouchEvent(true);
    return super.dispatchTouchEvent(event);
}

@SuppressWarnings("NullableProblems")
@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (changeLocationlistener != null) {
                changeLocationlistener.locationChange("change self");
            } else {
                changeLocationlistener = null;
            }

            memonyX = (int) event.getX();
            memonyY = (int) event.getY();
            checkMode(memonyX, memonyY);
            break;
        case MotionEvent.ACTION_MOVE: {
            switch (MODE) {
                case MODE_ILLEGAL:
                    pressX = (int) event.getX();
                    pressY = (int) event.getY();
                    recoverFromIllegal(pressX, pressY);
                    postInvalidate();
                    break;
                case MODE_OUTSIDE:
                    //do nothing;
                    break;
                case MODE_INSIDE:
                    pressX = (int) event.getX();
                    pressY = (int) event.getY();
                    moveByTouch(pressX, pressY);
                    postInvalidate();
                    break;
                default:
                        /*MODE_POINT*/
                    pressX = (int) event.getX();
                    pressY = (int) event.getY();
                    mPaintLine.setColor(getContext().getResources().getColor(R.color.white));
                    moveByPoint(pressX, pressY);
                    postInvalidate();
                    break;
            }
        }
        break;
        case MotionEvent.ACTION_UP:
            mPaintLine.setColor(Color.WHITE);
            postInvalidate();
            break;
        default:
            break;
    }
    return true;
}

/*从非法状态恢复,这里处理的是达到最小值后能拉伸放大*/
private void recoverFromIllegal(int rx, int ry) {
    if ((rx > sX && ry > sY) && (rx < eX && ry < eY)) {
        MODE = MODE_ILLEGAL;
    } else {
        MODE = MODE_POINT;
    }
}

private void checkMode(int cx, int cy) {
    if (cx > sX && cx < eX && cy > sY && cy < eY) {
        MODE = MODE_INSIDE;
    } else if (nearbyPoint(cx, cy) < 4) {
        MODE = MODE_POINT;
    } else {
        MODE = MODE_OUTSIDE;
    }
}

/*判断点(inX,inY)是否靠近矩形的4个顶点*/
private int nearbyPoint(int inX, int inY) {
    if ((Math.abs(sX - inX) <= ACCURACY && (Math.abs(inY - sY) <= ACCURACY))) {/*left-up angle*/
        pointPosition = 0;
        return 0;
    }
    if ((Math.abs(eX - inX) <= ACCURACY && (Math.abs(inY - sY) <= ACCURACY))) {/*right-up  angle*/
        pointPosition = 1;
        return 1;
    }
    if ((Math.abs(sX - inX) <= ACCURACY && (Math.abs(inY - eY) <= ACCURACY))) {/*left-down angle*/
        pointPosition = 2;
        return 2;
    }
    if ((Math.abs(eX - inX) <= ACCURACY && (Math.abs(inY - eY) <= ACCURACY))) {/*right-down angle*/
        pointPosition = 3;
        return 3;
    }
    pointPosition = 100;
    return 100;
}

/*刷新矩形的坐标*/
private void refreshLocation(int isx, int isy, int iex, int iey) {
    this.sX = isx;
    this.sY = isy;
    this.eX = iex;
    this.eY = iey;
}

/*矩形随手指移动*/
private void moveByTouch(int mx, int my) {/*move center point*/
    int dX = mx - memonyX;
    int dY = my - memonyY;

    sX += dX;
    sY += dY;

    eX = sX + coverWidth;
    eY = sY + coverHeight;

    memonyX = mx;
    memonyY = my;

}

/*检测矩形是否达到最小值*/
private boolean checkLegalRect(int cHeight, int cWidth) {
    return (cHeight > minHeight && cWidth > minWidth);
}

/*点击顶点附近时的缩放处理*/
@SuppressWarnings("SuspiciousNameCombination")
private void moveByPoint(int bx, int by) {
    switch (pointPosition) {
        case 0:/*left-up*/
            coverWidth = Math.abs(eX - bx);
            coverHeight = Math.abs(eY - by);
            //noinspection SuspiciousNameCombination
            if (!checkLegalRect(coverWidth, coverHeight)) {
                MODE = MODE_ILLEGAL;
            } else {
                mBitmapRectBlack = null;
                mBitmapRectBlack = makeBitmap(coverWidth, coverHeight, 0xff000000, coverWidth, coverHeight);
                refreshLocation(bx, by, eX, eY);
            }
            break;
        case 1:/*right-up*/
            coverWidth = Math.abs(bx - sX);
            coverHeight = Math.abs(eY - by);
            if (!checkLegalRect(coverWidth, coverHeight)) {
                MODE = MODE_ILLEGAL;
            } else {
                mBitmapRectBlack = null;
                mBitmapRectBlack = makeBitmap(coverWidth, coverHeight, 0xff000000, coverWidth, coverHeight);
                refreshLocation(sX, by, bx, eY);
            }
            break;
        case 2:/*left-down*/
            coverWidth = Math.abs(eX - bx);
            coverHeight = Math.abs(by - sY);
            if (!checkLegalRect(coverWidth, coverHeight)) {
                MODE = MODE_ILLEGAL;
            } else {
                mBitmapRectBlack = null;
                mBitmapRectBlack = makeBitmap(coverWidth, coverHeight, 0xff000000, coverWidth, coverHeight);
                refreshLocation(bx, sY, eX, by);
            }
            break;
        case 3:/*right-down*/
            coverWidth = Math.abs(bx - sX);
            coverHeight = Math.abs(by - sY);
            if (!checkLegalRect(coverWidth, coverHeight)) {
                MODE = MODE_ILLEGAL;
            } else {
                mBitmapRectBlack = null;
                mBitmapRectBlack = makeBitmap(coverWidth, coverHeight, 0xff000000, coverWidth, coverHeight);
                refreshLocation(sX, sY, bx, by);
            }
            break;
        default:
            break;
    }
}

public void setLocationListener(onLocationListener locationListener) {
    this.locationListener = locationListener;
}

public interface onLocationListener {
    public void locationRect(int startX, int startY, int endX, int endY);
}

public interface onChangeLocationlistener {
    @SuppressWarnings("SameParameterValue")
    public void locationChange(String msg);
}

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //获取屏幕的宽和高
    int screenWidth = canvas.getWidth();
    int screenHeight = canvas.getHeight();

    mPaint.setFilterBitmap(false);
    int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null,
            Canvas.MATRIX_SAVE_FLAG |
                    Canvas.CLIP_SAVE_FLAG |
                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                    Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                    Canvas.CLIP_TO_LAYER_SAVE_FLAG);

    canvas.drawBitmap(mBitmapCover, 0, 0, mPaint);
    mPaint.setXfermode(xfermode);
    canvas.drawBitmap(mBitmapRectBlack, sX, sY, mPaint);
    if (locationListener != null) {
        locationListener.locationRect(sX, sY, eX, eY);
    }
    mPaint.setXfermode(null);
    canvas.restoreToCount(sc);
    //canvas.drawLine((float) sX - EDGE_WIDTH, (float) sY - EDGE_WIDTH, (float) eX + EDGE_WIDTH, (float) sY - EDGE_WIDTH, mPaintLine);/*up -*/
    //canvas.drawLine((float) sX - EDGE_WIDTH, (float) eY + EDGE_WIDTH, (float) eX + EDGE_WIDTH, (float) eY + EDGE_WIDTH, mPaintLine);/*down -*/
    //canvas.drawLine((float) sX - EDGE_WIDTH, (float) sY - EDGE_WIDTH, (float) sX - EDGE_WIDTH, (float) eY + EDGE_WIDTH, mPaintLine);/*left |*/
    //canvas.drawLine((float) eX + EDGE_WIDTH, (float) sY - EDGE_WIDTH, (float) eX + EDGE_WIDTH, (float) eY + EDGE_WIDTH, mPaintLine);/*righ |*/
    //TODO  画出八个角
    float left = sX - EDGE_WIDTH;
    float top = sY - EDGE_WIDTH;
    float right = eX + EDGE_WIDTH;
    float bottom = eY + EDGE_WIDTH;
   /* //如果矩形框 已经超出屏幕 不再继续移动
    if (sX <= 0 || eX >= screenWidth || sY <= 0 || eY >= screenHeight) {
        return ;
    }*/
    if (!isFirst) {
        isFirst = true;
        slideTop = (int) top;
        slideBottom = (int) bottom;
    }
    Paint paint = new Paint();
    paint.setColor(Color.GREEN);
    //1 左上
    canvas.drawRect(left, top, left + ScreenRate,
            top + CORNER_WIDTH, paint);
    canvas.drawRect(left, top, left + CORNER_WIDTH, top
            + ScreenRate, paint);
    //2 右上
    canvas.drawRect(right - ScreenRate, top, right,
            top + CORNER_WIDTH, paint);
    canvas.drawRect(right - CORNER_WIDTH, top, right, top
            + ScreenRate, paint);
    //3 左下
    canvas.drawRect(left, bottom - CORNER_WIDTH, left
            + ScreenRate, bottom, paint);
    canvas.drawRect(left, bottom - ScreenRate,
            left + CORNER_WIDTH, bottom, paint);
    //4 右下
    canvas.drawRect(right - ScreenRate, bottom - CORNER_WIDTH,
            right, bottom, paint);
    canvas.drawRect(right - CORNER_WIDTH, bottom - ScreenRate,
            right, bottom, paint);

    //绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE
    slideTop += SPEEN_DISTANCE;
    if (slideTop >= bottom) {
        slideTop = (int) top;
    }
    canvas.drawRect(left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH / 2, right - MIDDLE_LINE_PADDING, slideTop + MIDDLE_LINE_WIDTH / 2, paint);
    //画扫描框下面的字
    paint.setColor(Color.WHITE);
    paint.setTextSize(TEXT_SIZE * density);
    paint.setAlpha(0x40);
    paint.setTypeface(Typeface.create("System", Typeface.BOLD));
    canvas.drawText(getResources().getString(R.string.scan_text), left + 30, (float) (bottom + (float) TEXT_PADDING_TOP * density), paint);
    paint.setColor(getResources().getColor(R.color.b_commit));
    canvas.drawText(getResources().getString(R.string.scan_notice), left, (float) (bottom + (float) TEXT_PADDING_TOP * density + 50), paint);

    Collection<ResultPoint> currentPossible = possibleResultPoints;
    Collection<ResultPoint> currentLast = lastPossibleResultPoints;
    if (currentPossible.isEmpty()) {
        lastPossibleResultPoints = null;
    } else {
        possibleResultPoints = new HashSet<ResultPoint>(5);
        lastPossibleResultPoints = currentPossible;
        paint.setAlpha(OPAQUE);
        paint.setColor(resultPointColor);
        for (ResultPoint point : currentPossible) {
            canvas.drawCircle(left + point.getX(), top
                    + point.getY(), 6.0f, paint);
        }
    }
    if (currentLast != null) {
        paint.setAlpha(OPAQUE / 2);
        paint.setColor(resultPointColor);
        for (ResultPoint point : currentLast) {
            canvas.drawCircle(left + point.getX(), top
                    + point.getY(), 3.0f, paint);
        }
    }

    //只刷新扫描框的内容,其他地方不刷新
    postInvalidateDelayed(ANIMATION_DELAY, (int) left, (int) top,
            (int) right, (int) bottom);

}

public void drawViewfinder() {
    resultBitmap = null;
    invalidate();
}

/**
 * Draw a bitmap with the result points highlighted instead of the live
 * scanning display.
 *
 * @param barcode An image of the decoded barcode.
 */
public void drawResultBitmap(Bitmap barcode) {
    resultBitmap = barcode;
    invalidate();
}

public void addPossibleResultPoint(ResultPoint point) {
    possibleResultPoints.add(point);
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值