package com.forfan.bigbang.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.forfan.bigbang.R;
import com.forfan.bigbang.util.ViewUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/11/28.
*/
public class MarkSizeView extends View {
private static final int DEFAULT_MARKED_COLOR = Color.parseColor("#00000000");
private static final int DEFAULT_UNMARKED_COLOR = Color.parseColor("#80000000");
private static final int DEFAULT_STROKE_COLOR = Color.parseColor("#009688");
private static final int DEFAULT_STROKE_WIDTH = 2;//dp
private static final int DEFAULT_VERTEX_COLOR = Color.parseColor("#009688");
private static final int DEFAULT_CONFIRM_BUTTON_RES = R.mipmap.ic_done_white_36dp;
private static final int DEFAULT_CANCEL_BUTTON_RES = R.mipmap.ic_close_capture;
private static final int BUTTON_EXTRA_WIDTH = ViewUtil.dp2px(8);
private static final int DEFAULT_VERTEX_WIDTH=20;//dp
private int markedColor = DEFAULT_MARKED_COLOR;
private int unmarkedColor = DEFAULT_UNMARKED_COLOR;
private int strokeColor = DEFAULT_STROKE_COLOR;
private int strokeWidth = (int) ViewUtil.dp2px(DEFAULT_STROKE_WIDTH);//dp
private int vertexColor = DEFAULT_VERTEX_COLOR;
private int confirmButtonRes = DEFAULT_CONFIRM_BUTTON_RES;
private int cancelButtonRes = DEFAULT_CANCEL_BUTTON_RES;
private int vertexWidth = (int) ViewUtil.dp2px(DEFAULT_VERTEX_WIDTH);
private int mActionGap;
private Paint unMarkPaint,markPaint,vertexPaint, mBitPaint;
private int downX,downY;
private int startX,startY;
private int endX,endY;
private Rect markedArea;
private Rect confirmArea,cancelArea;
private RectF ltVer,rtVer,lbVer,rbVer;
private boolean isValid=false;
private boolean isUp=false;
private boolean isMoveMode=false;
private boolean isAdjustMode=false;
private boolean isButtonClicked=false;
private int adjustNum = 0;
private Bitmap confirmBitmap,cancelBitmap;
private onClickListener mOnClickListener;
private boolean isMarkRect=true;
private GraphicPath mGraphicPath;
public MarkSizeView(Context context) {
super(context);
init(context,null);
}
public MarkSizeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
private void init(Context context,AttributeSet attrs){
if (attrs!=null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MarkSizeView);
markedColor=typedArray.getColor(R.styleable.MarkSizeView_markedColor,DEFAULT_MARKED_COLOR);
unmarkedColor=typedArray.getColor(R.styleable.MarkSizeView_unMarkedColor,DEFAULT_UNMARKED_COLOR);
strokeColor=typedArray.getColor(R.styleable.MarkSizeView_strokeColor,DEFAULT_STROKE_COLOR);
strokeWidth=typedArray.getDimensionPixelSize(R.styleable.MarkSizeView_strokeWidth, (int) ViewUtil.dp2px(DEFAULT_STROKE_WIDTH));
vertexColor=typedArray.getColor(R.styleable.MarkSizeView_vertexColor,DEFAULT_VERTEX_COLOR);
vertexWidth=typedArray.getDimensionPixelSize(R.styleable.MarkSizeView_vertexWidth, (int) ViewUtil.dp2px(DEFAULT_VERTEX_WIDTH));
confirmButtonRes =typedArray.getResourceId(R.styleable.MarkSizeView_confirmButtonRes,DEFAULT_CONFIRM_BUTTON_RES);
cancelButtonRes=typedArray.getResourceId(R.styleable.MarkSizeView_cancleButtonRes,DEFAULT_CANCEL_BUTTON_RES);
}
unMarkPaint=new Paint();
unMarkPaint.setColor(unmarkedColor);
unMarkPaint.setAntiAlias(true);
markPaint=new Paint();
markPaint.setColor(markedColor);
markPaint.setStyle(Paint.Style.FILL_AND_STROKE);
markPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
markPaint.setColor(markedColor);
markPaint.setStrokeWidth(strokeWidth);
markPaint.setAntiAlias(true);
vertexPaint=new Paint();
vertexPaint.setColor(vertexColor);
vertexPaint.setAntiAlias(true);
mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitPaint.setFilterBitmap(true);
mBitPaint.setDither(true);
markedArea=new Rect();
confirmArea=new Rect();
cancelArea=new Rect();
ltVer=new RectF();
rtVer=new RectF();
lbVer=new RectF();
rbVer=new RectF();
confirmBitmap= BitmapFactory.decodeResource(getResources(), confirmButtonRes);
cancelBitmap = BitmapFactory.decodeResource(getResources(),cancelButtonRes);
mActionGap = (int) ViewUtil.dp2px(15);
mGraphicPath=new GraphicPath();
}
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height=getHeight();
//draw unmarked
canvas.drawRect(0,0,width,height,unMarkPaint);
//draw marked
if (isMarkRect){
if (isValid || !isEnabled()) {
canvas.drawRect(markedArea, markPaint);
}
if (!isEnabled()){
return;
}
//draw vertex
if (isValid&&isUp) {
canvas.drawOval(ltVer, vertexPaint);
canvas.drawOval(rtVer, vertexPaint);
canvas.drawOval(lbVer, vertexPaint);
canvas.drawOval(rbVer, vertexPaint);
}
//draw button
if (isValid&&isUp) {
canvas.drawBitmap(confirmBitmap,null,confirmArea,mBitPaint);
canvas.drawBitmap(cancelBitmap,null,cancelArea,mBitPaint);
}
}else {
if (!isEnabled()){
return;
}
if (isUp) {
if (isValid) {
Path path = new Path();
if (mGraphicPath.size() > 1) {
path.moveTo(mGraphicPath.pathX.get(0), mGraphicPath.pathY.get(0));
for (int i = 1; i < mGraphicPath.size(); i++) {
path.lineTo(mGraphicPath.pathX.get(i), mGraphicPath.pathY.get(i));
}
} else {
return;
}
canvas.drawPath(path, markPaint);
}
}else {
if (mGraphicPath.size() > 1) {
for (int i = 1; i < mGraphicPath.size(); i++) {
canvas.drawLine(mGraphicPath.pathX.get(i-1), mGraphicPath.pathY.get(i-1),mGraphicPath.pathX.get(i), mGraphicPath.pathY.get(i),markPaint);
}
}
}
//draw button
if (isValid&&isUp) {
canvas.drawBitmap(confirmBitmap,null,confirmArea,mBitPaint);
canvas.drawBitmap(cancelBitmap,null,cancelArea,mBitPaint);
}
}
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()){
return false;
}
int x= (int) event.getX();
int y= (int) event.getY();
if (isMarkRect) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isUp = false;
isAdjustMode = false;
isMoveMode = false;
isButtonClicked = false;
isValid = false;
adjustNum = 0;
downX = x;
downY = y;
if (mOnClickListener != null) {
mOnClickListener.onTouch();
}
if (isAreaContainPoint(confirmArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onConfirm(markedArea);
}
} else if (isAreaContainPoint(cancelArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onCancel();
isValid = false;
startX = startY = endX = endY = 0;
adjustMark(0, 0);
}
} else if (isAreaContainPoint(ltVer,x, y)) {
isAdjustMode = true;
adjustNum = 1;
} else if (isAreaContainPoint(rtVer,x, y)) {
isAdjustMode = true;
adjustNum = 2;
} else if (isAreaContainPoint(lbVer,x, y)) {
isAdjustMode = true;
adjustNum = 3;
} else if (isAreaContainPoint(rbVer,x, y)) {
isAdjustMode = true;
adjustNum = 4;
} else if (markedArea.contains(x, y)) {
isMoveMode = true;
} else {
isMoveMode = false;
startX = (int) event.getX();
startY = (int) event.getY();
endX = startX;
endY = startY;
}
break;
case MotionEvent.ACTION_MOVE:
if (isButtonClicked) {
break;
}
adjustMark(x, y);
break;
case MotionEvent.ACTION_UP:
isUp = true;
if (isButtonClicked) {
break;
}
adjustMark(x, y);
startX = markedArea.left;
startY = markedArea.top;
endX = markedArea.right;
endY = markedArea.bottom;
if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5) {
//显示在选区的内底部
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
} else if (endY > getHeight() - confirmBitmap.getHeight() * 3) {
//显示在选区的上面
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
} else {
//显示在选区的下面
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
}
if (cancelArea.left<0){
int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
}
if (!isValid) {
if (mOnClickListener != null) {
mOnClickListener.onCancel();
}
}
break;
case MotionEvent.ACTION_CANCEL:
isUp = true;
break;
}
}else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isUp = false;
isAdjustMode = false;
isMoveMode = false;
isButtonClicked = false;
isValid = false;
adjustNum = 0;
downX = x;
downY = y;
if (mOnClickListener != null) {
mOnClickListener.onTouch();
}
if (isAreaContainPoint(confirmArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onConfirm(mGraphicPath);
}
} else if (isAreaContainPoint(cancelArea,x, y)) {
isButtonClicked = true;
isValid = true;
if (mOnClickListener != null) {
mOnClickListener.onCancel();
isValid = false;
startX = startY = endX = endY = 0;
adjustMark(0, 0);
}
mGraphicPath.clear();
} else {
isMoveMode = false;
startX = (int) event.getX();
startY = (int) event.getY();
endX = startX;
endY = startY;
mGraphicPath.clear();
mGraphicPath.addPath(x,y);
}
break;
case MotionEvent.ACTION_MOVE:
if (isButtonClicked) {
break;
}
mGraphicPath.addPath(x,y);
break;
case MotionEvent.ACTION_UP:
isUp = true;
if (isButtonClicked) {
break;
}
mGraphicPath.addPath(x,y);
startX = mGraphicPath.getLeft();
startY = mGraphicPath.getTop();
endX = mGraphicPath.getRight();
endY = mGraphicPath.getBottom();
if ((endX-startX)*(endY-startY)>200){
isValid=true;
}
markedArea.set(startX,startY,endX,endY);
if (endY < getHeight() - confirmBitmap.getHeight() * 3){
//显示在选区的下面
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
} else
if (startY > confirmBitmap.getHeight() * 3) {
//显示在选区的上面
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
}else
// if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5)
{
//显示在选区的内底部
confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
}
if (cancelArea.left<0){
int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
}
if (!isValid) {
if (mOnClickListener != null) {
mOnClickListener.onCancel();
}
}
break;
case MotionEvent.ACTION_CANCEL:
isUp = true;
break;
}
}
postInvalidate();
return true;
}
private boolean isAreaContainPoint(Rect area,int x,int y){
Rect newArea=new Rect(area.left-BUTTON_EXTRA_WIDTH,area.top-BUTTON_EXTRA_WIDTH,area.right+BUTTON_EXTRA_WIDTH,area.bottom+BUTTON_EXTRA_WIDTH);
if (newArea.contains(x,y)){
return true;
}
return false;
}
private boolean isAreaContainPoint(RectF area,int x,int y){
RectF newArea=new RectF(area.left-BUTTON_EXTRA_WIDTH,area.top-BUTTON_EXTRA_WIDTH,area.right+BUTTON_EXTRA_WIDTH,area.bottom+BUTTON_EXTRA_WIDTH);
if (newArea.contains(x,y)){
return true;
}
return false;
}
private void adjustMark(int x, int y) {
if (isAdjustMode){
int moveMentX = x-downX;
int moveMentY = y-downY;
switch (adjustNum){
case 1:
startX=startX+moveMentX;
startY=startY+moveMentY;
break;
case 2:
endX=endX+moveMentX;
startY=startY+moveMentY;
break;
case 3:
startX=startX+moveMentX;
endY=endY+moveMentY;
break;
case 4:
endX=endX+moveMentX;
endY=endY+moveMentY;
break;
}
downX=x;
downY=y;
}else if (isMoveMode){
int moveMentX = x-downX;
int moveMentY = y-downY;
startX=startX+moveMentX;
startY=startY+moveMentY;
endX=endX+moveMentX;
endY=endY+moveMentY;
downX=x;
downY=y;
}else {
endX = x;
endY = y;
}
markedArea.set(Math.min(startX, endX), Math.min(startY, endY), Math.max(startX, endX), Math.max(startY, endY));
ltVer.set(markedArea.left - vertexWidth / 2, markedArea.top - vertexWidth / 2, markedArea.left + vertexWidth / 2, markedArea.top + vertexWidth / 2);
rtVer.set(markedArea.right - vertexWidth / 2, markedArea.top - vertexWidth / 2, markedArea.right + vertexWidth / 2, markedArea.top + vertexWidth / 2);
lbVer.set(markedArea.left - vertexWidth / 2, markedArea.bottom - vertexWidth / 2, markedArea.left + vertexWidth / 2, markedArea.bottom + vertexWidth / 2);
rbVer.set(markedArea.right - vertexWidth / 2, markedArea.bottom - vertexWidth / 2, markedArea.right + vertexWidth / 2, markedArea.bottom + vertexWidth / 2);
if (markedArea.height()*markedArea.width()>200){
isValid=true;
}else {
isValid = false;
}
}
public interface onClickListener{
void onConfirm(Rect markedArea);
void onConfirm(GraphicPath path);
void onCancel();
void onTouch();
}
public void setmOnClickListener(onClickListener mOnClickListener) {
this.mOnClickListener = mOnClickListener;
}
public void setUnmarkedColor(int unmarkedColor) {
this.unmarkedColor = unmarkedColor;
unMarkPaint.setColor(unmarkedColor);
invalidate();
}
public void reset(){
isUp=false;
isValid=false;
startX=startY=endX=endY=0;
mGraphicPath=new GraphicPath();
adjustMark(0,0);
}
public void setIsMarkRect(boolean isMarkRect){
this.isMarkRect=isMarkRect;
}
public static class GraphicPath implements Parcelable {
protected GraphicPath(Parcel in) {
int size=in.readInt();
int[] x=new int[size];
int[] y=new int[size];
in.readIntArray(x);
in.readIntArray(y);
pathX=new ArrayList<>();
pathY=new ArrayList<>();
for (int i=0;i<x.length;i++){
pathX.add(x[i]);
}
for (int i=0;i<y.length;i++){
pathY.add(y[i]);
}
}
public static final Creator<GraphicPath> CREATOR = new Creator<GraphicPath>() {
@Override
public GraphicPath createFromParcel(Parcel in) {
return new GraphicPath(in);
}
@Override
public GraphicPath[] newArray(int size) {
return new GraphicPath[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(pathX.size());
dest.writeIntArray(getXArray());
dest.writeIntArray(getYArray());
}
public List<Integer> pathX;
public List<Integer> pathY;
public GraphicPath(){
pathX=new ArrayList<>();
pathY=new ArrayList<>();
}
private int[] getXArray(){
int[] x=new int[pathX.size()];
for (int i=0;i<x.length;i++){
x[i]=pathX.get(i);
}
return x;
}
private int[] getYArray(){
int[] y=new int[pathY.size()];
for (int i=0;i<y.length;i++){
y[i]=pathY.get(i);
}
return y;
}
public void addPath(int x,int y){
pathX.add(x);
pathY.add(y);
}
public void clear(){
pathX.clear();
pathY.clear();
}
public int getTop(){
int min=pathY.size()>0?pathY.get(0):0;
for (int y:pathY){
if (y<min){
min=y;
}
}
return min;
}
public int getLeft(){
int min=pathX.size()>0?pathX.get(0):0;
for (int x:pathX){
if (x<min){
min=x;
}
}
return min;
}
public int getBottom(){
int max=pathY.size()>0?pathY.get(0):0;
for (int y:pathY){
if (y>max){
max=y;
}
}
return max;
}
public int getRight(){
int max=pathX.size()>0?pathX.get(0):0;
for (int x:pathX){
if (x>max){
max=x;
}
}
return max;
}
public int size(){
return pathY.size();
}
}
}