自定義具有縮放、旋轉、移動等操作功能的視圖容器

一、簡陋的自定義view(SurfaceView繪製可縮放、旋轉、移動的簡單視圖)

package com.ahtelit.zbv.myapplication;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by Administrator on 2018/4/19.
 * qzx
 */

public class SimpleTransformView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private boolean isDestroy;
    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    private Paint mPaint;

    //繪製的位置和大小和上下左右的等數據
    private RectF rectF;//canvas繪製矩形有兩種:一種是int的還有就是這個float
    private float rectf_range_width = 200.0f;//矩形的長度
    private float rectf_range_height = 200.0f;
    private static final float TIPS_MARGIN = 80.0f;
    private static final float TIPS_RANGE = 100.0f;//tips的矩形高度
    private static final float DASH_RANGE = 10.0F;//觸碰虛線生效的範圍

    private static final float Circle_Radius = 20.0f;//可縮放的圓圈半徑
    private float side_left;
    private float side_top;
//    private float side_right;
//    private float side_bottom;

    private float pad_width;
    private float pad_height;

    //繪製的視圖類型
    private int drawType = 0;//默認爲文本類型
    private static final int TYPE_TEXT = 0;//文本
    private static final int TYPE_IMG = 1;//圖片

    public SimpleTransformView(Context context) {
        this(context, null);
    }

    public SimpleTransformView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleTransformView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initConfig();
    }

    private void initConfig() {
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);

        //配置基礎的畫筆參數
        mPaint = new Paint();
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
//        mPaint.setStyle(Paint.Style.STROKE);//描邊繪製

        //保持常亮
        setKeepScreenOn(true);

        //觸摸可以得到焦點
        setFocusable(true);
        setFocusableInTouchMode(true);

        //默認繪製的視圖大小---矩形
        rectF = new RectF(100, 100, 100 + rectf_range_width, 100 + rectf_range_height);
        side_left = rectF.left;
        side_top = rectF.top;
//        side_right=rectF.left+RECTF_RANGE;
//        side_bottom=rectF.top+RECTF_RANGE;

        //獲取手機屏幕大小
        DisplayMetrics dm = getResources().getDisplayMetrics();
        pad_width = dm.widthPixels;
        pad_height = dm.heightPixels;
    }

//    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
//    public SimpleTransformView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
//        super(context, attrs, defStyleAttr, defStyleRes);
//    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        new Thread(this).start();
        isDestroy = false;

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        isDestroy = true;

    }

    @Override
    public void run() {

        while (!isDestroy) {
            try {
                mCanvas = mSurfaceHolder.lockCanvas();
                drawUI();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (mCanvas != null)
                    mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }

        }

    }

    private String testText = "七子笑";
    private String tipsText = "旋轉";
    private float hadRotateAngle = 0;//已經旋轉過的角度
    private float rotateAngle = 0;//要旋轉的角度
    private String tipsDegree = 0 + "°";//顯示角度提示
    private float wordSize = 20.0f;

    private void drawUI() {
        if (drawType == TYPE_TEXT) {

            mCanvas.drawColor(Color.WHITE);//清屏操作
//            if (isCanRotate) {
            mCanvas.save();
                /*
                如果不設置旋轉點默認是起始位置,可能使(0,0)
                並且Canvas的旋轉都是數學座標系的Y軸向上的爲其實0度旋轉
                --->據說旋轉的是畫布,視圖屬性還是在原來的位置的
                 */
            mCanvas.rotate(rotateAngle, rectF.centerX(), rectF.centerY());
            commonView();
            mCanvas.restore();
//            } else {
//                commonView();
//            }

            /*所以fontMetrics的bottom是正數=bottom-baseline;的top是負數=top-baseline
              除了fontMetrics.leading是負數=top-ascent,其餘的都是和baseline掛鉤
             */
//            float baseline=(side_top+side_bottom-(fontMetrics.bottom+fontMetrics.top))/2;
            //通過FontMetrics的baseline繪製
//            mCanvas.drawText(testText,rectF.centerX(),baseline,mPaint);
        }

    }

    private void commonView() {
        //繪製文本視圖---背景、文字
        mPaint.setColor(Color.GRAY);
        mPaint.setStyle(Paint.Style.FILL);
        mCanvas.drawRect(rectF, mPaint);
        mPaint.setColor(Color.WHITE);
        mPaint.setTextAlign(Paint.Align.CENTER);//繪製在x,y虛擬矩形中間
//            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        mPaint.setTextSize(wordSize);
        mCanvas.drawText(testText, rectF.left + rectF.width() / 2, rectF.top + rectF.height() / 2, mPaint);

        //繪製縮放視圖
        if (isShowScaleView) {
            mPaint.setColor(Color.RED);
            mCanvas.drawCircle(rectF.left, rectF.top, Circle_Radius, mPaint);//左上角
            mCanvas.drawCircle(rectF.left, rectF.bottom, Circle_Radius, mPaint);//左下角
            mCanvas.drawCircle(rectF.right, rectF.top, Circle_Radius, mPaint);//右上角
            mCanvas.drawCircle(rectF.right, rectF.bottom, Circle_Radius, mPaint);//右下角
        }

        //繪製旋轉提示的文本和矩形背景
        if (isShowRotateView) {
            mPaint.setColor(Color.BLACK);
            mCanvas.drawRect(rectF.left, rectF.top - TIPS_MARGIN - TIPS_RANGE, rectF.right, rectF.top - TIPS_MARGIN, mPaint);
            mPaint.setColor(Color.WHITE);
            Paint.FontMetrics fontMetrics = new Paint.FontMetrics();
            float baseLine = (rectF.top * 2 - 2 * TIPS_MARGIN - TIPS_RANGE - (fontMetrics.top + fontMetrics.bottom)) / 2;
            tipsDegree = rotateAngle + "°";
            mCanvas.drawText(tipsDegree, rectF.left + rectF.width() / 2, baseLine, mPaint);

            //虛線---觸碰到可以旋轉
            mPaint.setColor(Color.GRAY);
            mPaint.setPathEffect(new DashPathEffect(new float[]{15, 3}, 0));
            mCanvas.drawLine(rectF.left + rectF.width() / 2, rectF.top, rectF.left + rectF.width() / 2, rectF.top - TIPS_MARGIN, mPaint);

        } else {
            mPaint.setColor(Color.GRAY);
            mCanvas.drawRect(rectF.left, rectF.top - TIPS_MARGIN - TIPS_RANGE, rectF.right, rectF.top - TIPS_MARGIN, mPaint);
            mPaint.setColor(Color.WHITE);
            Paint.FontMetrics fontMetrics = new Paint.FontMetrics();
            float baseLine = (rectF.top * 2 - 2 * TIPS_MARGIN - TIPS_RANGE - (fontMetrics.top + fontMetrics.bottom)) / 2;
            mCanvas.drawText(tipsText, rectF.left + rectF.width() / 2, baseLine, mPaint);
        }
    }

//    private static final float INVALID_RANGE = 10;//設置無效的範圍點

    private float downX;//觸摸點的起始位置-X
    private float downY;//觸摸點的起始位置-Y

    private boolean isCanMove = false;
    private boolean isShowScaleView = false;//是否顯示可縮放的view
    private boolean isCanScale = false;
    private boolean isCanRotate = false;
    private boolean isShowRotateView = false;//是否顯示可旋轉的view
//    private boolean isHadRotateDegree = false;//是否有旋轉的操作即有旋轉角度

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                //有旋轉角度
                if (hadRotateAngle != 0) {
                    Log.d("zbv", "右旋轉角=" + hadRotateAngle);
                    float currentLocations[] = getBeforeViewLocation(hadRotateAngle, event.getX(), event.getY());
                    downX = currentLocations[0];
                    downY = currentLocations[1];
                } else {
                    downX = event.getX();
                    downY = event.getY();
                }
                if (isShowRotateView) {
                    if (downX > (rectF.left + rectF.width() / 2 - DASH_RANGE) && downX < (rectF.left + rectF.width() / 2 + DASH_RANGE)
                            && downY < rectF.top && (downY > rectF.top - TIPS_MARGIN)) {
                        Log.d("zbv", "觸碰到虛線了");
                        isCanRotate = true;
                    }
                } else {
                    if (rectF.contains(downX, downY)) {
                        Log.d("zbv", "在繪製範圍內可以顯示縮放視圖");
                        isShowScaleView = true;
                        isCanMove = true;
                    } else {
                        Log.d("zbv", "繪製區域外隱藏縮放視圖");
                        isShowScaleView = false;
                    }

                    if (downX > rectF.left && downX < rectF.right && downY > (rectF.top - TIPS_MARGIN - TIPS_RANGE)
                            && downY < (rectF.top - TIPS_MARGIN)) {
                        Log.d("zbv", "觸摸到旋轉區域");
                        isShowRotateView = true;
                        isCanMove = false;
                    }

                    //觸摸到可縮放區域-左上、左下、右上、右下
                    if (((rectF.left - Circle_Radius) < downX && downX < (rectF.left + Circle_Radius)
                            && (rectF.top - Circle_Radius) < downY && downY < (rectF.top + Circle_Radius))
                            || ((rectF.left - Circle_Radius) < downX && downX < (rectF.left + Circle_Radius)
                            && (rectF.bottom - Circle_Radius) < downY && downY < (rectF.bottom + Circle_Radius))
                            || ((rectF.right - Circle_Radius) < downX && downX < (rectF.right + Circle_Radius)
                            && (rectF.top - Circle_Radius) < downY && downY < (rectF.top + Circle_Radius))
                            || ((rectF.right - Circle_Radius) < downX && downX < (rectF.right + Circle_Radius)
                            && (rectF.bottom - Circle_Radius) < downY && downY < (rectF.bottom + Circle_Radius))) {
                        Log.d("zbv", "觸摸到要縮放的視圖區域了");
                        isCanScale = true;
                        isCanMove = false;//不可以移動了
                        //重置觸摸點爲了縮放
                        downX=event.getX();
                        downY=event.getY();
                    }

//                    if (event.getX() > (rectF.left + rectF.width() / 2 - DASH_RANGE) && event.getX() < (rectF.left + rectF.width() / 2 + DASH_RANGE)
//                            && event.getY() < rectF.top && (event.getY() > rectF.top + TIPS_MARGIN)) {
//                        Log.d("zbv", "觸碰到虛線了");
//                        isCanRotate = true;
//                    }
                }

                break;
            case MotionEvent.ACTION_MOVE:
                if (isCanMove) {
                    if (!rectF.contains(event.getX(), event.getY())) {
//                        Log.d("zbv", "移動手指出了繪製視圖"+rectf_range_width);
                        rectF.left = event.getX();
                        rectF.top = event.getY();
                        rectF.right = rectF.left + rectf_range_width;
                        rectF.bottom = rectF.top + rectf_range_height;
                        side_left = rectF.left;
                        side_top = rectF.top;

                    } else {
                        Log.d("zbv", "移動手指仍在繪製視圖");
                    }
                }
                if (isCanScale) {
                    rectF.left = side_left;
                    rectF.left += (event.getX() - downX);
                    rectf_range_width = rectF.right - rectF.left;
//                        Log.d("zbv","scale of rectLeft="+rectF.left+";width="+rectf_range_width);
                    rectF.top = side_top;
                    rectF.top += (event.getY() - downY);
                    rectf_range_height = rectF.bottom - rectF.top;
//                        Log.d("zbv","scale of rectLeft="+rectF.right+";height="+rectf_range_height);
                }
                if (isCanRotate) {
                    //計算兩直線間的角度---矩形中心點、其實觸摸點、移動的觸摸點
                    float angle_1 = (float) Math.atan2(downY - (rectF.top + rectF.height() / 2), downX - (rectF.left + rectF.width() / 2));
                    float angle_2 = (float) Math.atan2(event.getY() - (rectF.top + rectF.height() / 2), event.getX() - (rectF.left + rectF.width() / 2));
                    int jiaodu_1 = (int) Math.toDegrees(angle_1);
                    int jiaodu_2 = (int) Math.toDegrees(angle_2);

                    rotateAngle = jiaodu_2 - jiaodu_1;

//                    Log.d("zbv","rotateAngle="+rotateAngle);

                    if (rotateAngle > 180.0f) {
                        rotateAngle -= 360.0f;
                    }

//                    Log.d("zbv", "起始觸摸點到中心點角度爲=" + angle_1 + ";角度爲=" + jiaodu_1
//                            + ";移動點到中心點角度爲=" + angle_2 + ";角度爲=" + jiaodu_2);
                }
                break;
            case MotionEvent.ACTION_UP:
                //擡起-如果可以縮放就置爲原始不縮放狀態
                if (isCanScale) {
                    isCanScale = false;
                }
                if (isCanRotate) {
                    isCanRotate = false;
                    isShowRotateView = false;
                    hadRotateAngle = rotateAngle;
                }
                break;
            //多點觸摸---當一根手指已經down
            case MotionEvent.ACTION_POINTER_DOWN:
                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
        }
        return true;
    }

    /*
    爲了處理canvas旋轉導致的視圖屬性沒有變化從而使得觸摸點的無法生效
    所以反推原始點即:知道圓點、和旋轉後的點以及角度--->推導出旋轉前的點
     */
    private float[] getBeforeViewLocation(float angle, float dot_x, float dot_y) {
        float jiaodu = -angle;
        float[] locations = new float[2];
        double arcValue = Math.toRadians(jiaodu);
        float sin = (float) Math.sin(arcValue);
        float cos = (float) Math.cos(arcValue);
        locations[0] = (dot_x - (rectF.left + rectF.width() / 2)) * cos - (dot_y - (rectF.top + rectF.height() / 2)) * sin + rectF.left + rectF.width() / 2;
        locations[1] = (dot_y - (rectF.top + rectF.height() / 2)) * cos + (dot_x - (rectF.left + rectF.width() / 2)) * sin + rectF.top + rectF.height() / 2;
        return locations;
    }

    /**
     * 公開繪製類型的方法:
     * 文本---文本
     * 圖片---資源圖
     */
    public int getDrawType(int type) {
        if (type == TYPE_TEXT) {
            drawType = TYPE_TEXT;
        } else if (type == TYPE_IMG) {
            drawType = TYPE_IMG;
        }
        return 0;
    }
}

二、優化的可操作子視圖平移、旋轉、複製、刪除、編輯等操作

1、容器試圖TestLayout

package com.ahtelit.zbv.vphandler;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.icu.text.UnicodeSetSpanner;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import com.ahtelit.zbv.vphandler.zbvTools.QZXTools;

import java.security.acl.LastOwnerException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/4/25.
 * qzx
 */

public class TestLayout extends ViewGroup implements View.OnTouchListener, CustomBGView.CustomInterface {

    //添加演示層僅提供移動操作的標記
    private Boolean isShowActivtiy = false;

    public void setShowActivtiy(Boolean showActivtiy) {
        isShowActivtiy = showActivtiy;
    }

    private Context mContext;

    //哪種類型的視圖
    private int type;

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    private int touch_view_left;
    private int touch_view_right;
    private int touch_view_top;
    private int touch_view_bottom;
    private int touch_view_width;
    private int touch_view_height;

    //操作ID
    private static final int TRANSLATE = 0;
    private static final int SCALE = 1;
    private static final int ROTATE = 2;
    private static final int EDITMODE = 3;
    private static final int COPY = 4;
    private static final int DEL = 5;


    //    private List<View> allChildViews;
    private View touchView;

    public void setTouchView(View touchView) {
        this.touchView = touchView;
    }

    private CustomBGView cus_view;

    /**
     * key是int類型,value是int[]類型
     * 用於存儲添加的孩子在Layout中的位置以及添加的編號
     * 一開始就具有位置參數
     */
    private SparseArray<int[]> child_sarray;

    /**
     * 存儲角度---如果沒有臨時添加
     */
    private SparseArray<Integer> degree_sarray;

    //畫筆
//    private Paint mPaint;

//    private SharedPreferences sp_child;//用來保存當前子類的數量

    private int childCount;

    public void setChildCount(int childCount) {
        this.childCount = childCount;
    }
    //    private ScaleGestureDetector scaleGestureDetector;

    public TestLayout(Context context) {
        this(context, null);
    }

    public TestLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TestLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//        Log.d("zbv","初始化");
        initConfig(context);
    }

    private void initConfig(Context context) {
        mContext = context;

        //可以在Layout繪製
//        setWillNotDraw(false);
        //設置子類的繪製順序
        setChildrenDrawingOrderEnabled(true);
//        mPaint = new Paint();
//        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
//        mPaint.setStyle(Paint.Style.FILL);
//        mPaint.setStrokeCap(Paint.Cap.ROUND);
//        mPaint.setStrokeJoin(Paint.Join.ROUND);

//        sp_child = mContext.getSharedPreferences("save_view_count", Context.MODE_PRIVATE);

//        allChildViews = new ArrayList<View>();

//        scaleGestureDetector = new ScaleGestureDetector(mContext, this);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        Log.d("zbv","onMeasure");
        //默認的View中的onMeasure-建議重寫
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /*
         * 依據測量模式和尺寸重新計算---主要針對Wrap_Content---因爲父類無法準確測量
         */
        int mode_width = MeasureSpec.getMode(widthMeasureSpec);
        int size_width = MeasureSpec.getSize(widthMeasureSpec);//具體值或者Match_Parent
        int mode_height = MeasureSpec.getMode(heightMeasureSpec);
        int size_height = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = 0;

        //單行的寬高
        int lineWidth = 0;
        int lineHeight = 0;

//        QZXTools.logE("zbv", "childCount=" + getChildCount(), null);
        //得到layout中的子類個數
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
//            allChildViews.add(child);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            //判斷是否INVISIBLE或者GONE
            if (child.getVisibility() != View.VISIBLE) {
                //最後一個的話需要總結一下
                if (i == (childCount - 1)) {
                    width = Math.max(width, lineWidth);
                    height += lineHeight;
                }
                continue;
            }
            //測量子類
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            //子類的寬度+左右的padding+左右的margin
//            Log.d("zbv","getWidth="+child.getWidth()+";getMeasuredWidth="+child.getMeasuredWidth());

            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

            if (lineWidth + childWidth > size_width - getPaddingLeft() - getPaddingRight()) {
                //超過了父類的寬度->getPaddingLeft和Right是Layout自己的所以需要減去
                width = Math.max(width, lineWidth);
                lineWidth = childWidth;//另起一行的寬度
                lineHeight += childHeight;
            } else {
                lineWidth += childWidth;
                //可能一行排列中有的視圖高度會比之前高
                lineHeight = Math.max(lineHeight, childHeight);
            }
            //最後再比較一下寬度
            if (i == (childCount - 1)) {
                width = Math.max(width, lineWidth);
                height += lineHeight;
            }
        }

        setMeasuredDimension((mode_width == MeasureSpec.EXACTLY) ? size_width : width,
                (mode_height == MeasureSpec.EXACTLY) ? size_height : height);
    }

    private boolean isFirst = true;

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        //獲取layout中的所有子視圖個數
        int childCount = getChildCount();

        Log.d("zbv", "-------------------->onLayout" + childCount);

        int left_padding = getPaddingLeft();
        int top_padding = getPaddingTop();
//        if (isFirst) {
//            isFirst = false;
//            for (int i = 0; i < childCount; i++) {
//                //獲取對應i的子視圖
//                View childView = getChildAt(i);
////            //獲取最後的BG
////            if((childCount-1)==i){
////                cus_view=(CustomBGView) childView;
////            }
//                //添加觸摸監聽
//                childView.setOnTouchListener(this);
//                //因爲id要大於零---設置
//                childView.setId(i + 1);
//                MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
//                //依據給定的位置和margin以及padding設置子類的位置
//                childView.layout(child_sarray.get(i)[0], child_sarray.get(i)[1],
//                        left_padding + childView.getMeasuredWidth() + layoutParams.leftMargin,
//                        top_padding + childView.getMeasuredHeight() + layoutParams.topMargin);
//
//            }
//        } else {
        for (int i = 0; i < getChildCount(); i++) {
//                Log.d("zbv","childCount="+getChildCount());
            View childView = getChildAt(i);
            childView.setOnTouchListener(this);
            //手動設置childview的ID是從一開始的
            childView.setId(i + 1);
            MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
//                Log.d("zbv","childCount="+getChildCount()
//                        +";array_x="+child_sarray.get(i)[0]
//                        +";array_y="+child_sarray.get(i)[1]
//                        +";measureWidth="+childView.getMeasuredWidth()
//                        +";measureHeight="+childView.getMeasuredHeight()
//                        +";leftm="+layoutParams.leftMargin
//                        +";topm="+layoutParams.topMargin);
            //依據給定的位置和margin以及padding設置子類的位置

            QZXTools.logE("zbv", "------->child_array i=" + i, null);

//            if (child_sarray.get(i) != null) {
            childView.layout(child_sarray.get(i)[0], child_sarray.get(i)[1],
                    left_padding + childView.getMeasuredWidth() + layoutParams.leftMargin,
                    top_padding + childView.getMeasuredHeight() + layoutParams.topMargin);
//            }


//            //當最後一個加載完畢更新縮略圖----會調用很多次,每添加一個就會調用一次
//            if(i==(getChildCount()-1)){
//                Log.d("zbv","onLayout");
//                thumbnailInterface.notifyLayoutChange();
//            }
        }
//        }
    }

//    @Override
//    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//        Log.d("zbv","onSizeChanged");
//        super.onSizeChanged(w, h, oldw, oldh);
//        thumbnailInterface.notifyLayoutChange();
//    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
//        Log.d("zbv","onInterceptTouchEvent action="+ev.getAction()+";pointerCount="+ev.getPointerCount());
//        if(ev.getPointerCount()==2){
//            return true;
//
//        }
        return super.onInterceptTouchEvent(ev);
    }

    private static final float CIRCLE_RADIUS = 10;
    private static final int DEG_TIPS_DIVIDE = 30;
    private static final int DEG_TIP_MARGIN = 90;

//    @Override
//    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
//        //可以顯示提示Canvas
//        if(isCanShowTips){
//            for (View child : allChildViews){
//                child.setAlpha(0.7f);
//            }
//            //繪製四個角的圓點----左上、左下、右上、右下---紅色
//            mPaint.setColor(Color.RED);
//            canvas.drawCircle(touch_view_left,touch_view_top,CIRCLE_RADIUS,mPaint);
//            canvas.drawCircle(touch_view_left,touch_view_bottom,CIRCLE_RADIUS,mPaint);
//            canvas.drawCircle(touch_view_right,touch_view_top,CIRCLE_RADIUS,mPaint);
//            canvas.drawCircle(touch_view_right,touch_view_bottom,CIRCLE_RADIUS,mPaint);
//
////            //繪製旋轉度數的文本顯示---矩形背景綠色,文字白色
////            mPaint.setColor(Color.GREEN);
////            canvas.drawRect(touch_view_left+touch_view_width/2-DEG_TIPS_DIVIDE,
////                    touch_view_top+DEG_TIP_MARGIN,
////                    touch_view_left+touch_view_width/2+DEG_TIPS_DIVIDE,
////                    touch_view_top+DEG_TIP_MARGIN,mPaint);
//
//            mPaint.setColor(Color.YELLOW);
//            Rect bounds=new Rect();
//            String testText=-180+"°";
//            mPaint.getTextBounds(testText,0,testText.length(),bounds);
//            Paint.FontMetrics fontMetrics=mPaint.getFontMetrics();
//            float baseLine=touch_view_top+(bounds.height()+fontMetrics.top-fontMetrics.bottom)/2-fontMetrics.top;
//            canvas.drawText(0+"°",touch_view_left+bounds.width()/2,baseLine,mPaint);
//        }
//
//    }


//    private double startDistance;//一開始兩指間的距離
//    private double moveDistance;//移動中的兩指間距離
//    private boolean isCanWholeScale = false;
//    private boolean isGeasture = false;

    //    //是否可以移動---默認不可以移動
//    private boolean isCanMove=false;
    //四---處理觸摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
//        Log.d("zbv", "onTouchEvent action=" + event.getAction());
        //解決彈出軟鍵盤取消繪畫背景後的取消焦點問題
        if (event.getAction() == MotionEvent.ACTION_DOWN && editText != null && editText.isFocusable()) {
            if (event.getX() < touch_view_left || event.getX() > touch_view_right
                    || event.getY() < touch_view_top || event.getY() > touch_view_bottom) {
                Log.d("zbv", "編輯文本處於聚焦狀態---Layout onTouchEvent---在外邊");
                touchFoucusForEditText(false);
            }
        }

//        //多指操作---手勢操作
//        switch (event.getAction() & MotionEvent.ACTION_MASK) {
//            case MotionEvent.ACTION_DOWN:
//
//                break;
//            case MotionEvent.ACTION_MOVE:
//
//                if (event.getPointerCount() == 2 && isCanWholeScale) {
//                    float point_1_x = event.getX(0);
//                    float point_1_y = event.getY(0);
//
//                    float point_2_x = event.getX(1);
//                    float point_2_y = event.getY(1);
//
//                    moveDistance = Math.sqrt((Math.pow(point_2_x - point_1_x, 2) + Math.pow(point_2_y - point_1_y, 2)));
//
//                    Log.d("zbv","moveDistance="+moveDistance);
//
//                    //沒動會跳動
//                    if (moveDistance != startDistance) {
//                        //才真正縮放
//                        float ratio = (float) (moveDistance / startDistance);
//
//                        Log.d("zbv","ratio="+ratio);
//                        setScaleX(ratio);
//                        setScaleY(ratio);
//
//                    }
//                }
//
//                break;
//            case MotionEvent.ACTION_CANCEL:
//            case MotionEvent.ACTION_UP:
//
//                isCanWholeScale=false;
//
//                dismisssDraw();
//                break;
//            case MotionEvent.ACTION_POINTER_DOWN:
//
//                //只允許兩隻手指操作
//                if (event.getPointerCount() == 2) {
//
//                    float point_1_x = event.getX();
//                    float point_1_y = event.getY();
//
//                    float point_2_x = event.getX(1);
//                    float point_2_y = event.getY(1);
//
//                    startDistance = Math.sqrt((Math.pow(point_2_x - point_1_x, 2) + Math.pow(point_2_y - point_1_y, 2)));
//
//                    Log.d("zbv","startDistance="+startDistance);
//
//                    if (startDistance > 10.0f) {
//                        isCanWholeScale = true;
//                    }
//
//                }
//
//                break;
//            case MotionEvent.ACTION_POINTER_UP:
//
//
//                break;
//        }


//        scaleGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    // 滑動距離及座標 歸還父控件焦點iewPager
    private float xDistance, yDistance, xLast, yLast, mLeft;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
//        Log.d("zbv","dispatchTouchEvent action="+ev.getAction());
//        return super.dispatchTouchEvent(ev);

        //這個是重點告訴父佈局我這裏是ViewPager不要攔截觸摸事件,否則橫向操作會滑動V
        getParent().requestDisallowInterceptTouchEvent(true);
//        switch (ev.getAction()) {
//            case MotionEvent.ACTION_DOWN:
//                Log.d("touch", "ACTION_DOWN");
//                xDistance = yDistance = 0f;
//                xLast = ev.getX();
//                yLast = ev.getY();
//                mLeft = ev.getX();// 解決與側邊欄滑動衝突
//                break;
//            case MotionEvent.ACTION_MOVE:
//                final float curX = ev.getX();
//                final float curY = ev.getY();
//
//                xDistance += Math.abs(curX - xLast);
//                yDistance += Math.abs(curY - yLast);
//                xLast = curX;
//                yLast = curY;
//                if (mLeft < 100 || xDistance < yDistance) {
//                    getParent().requestDisallowInterceptTouchEvent(false);
//                }
//                break;
//            case MotionEvent.ACTION_UP:
//            case MotionEvent.ACTION_CANCEL:
//                break;
//        }
        return super.dispatchTouchEvent(ev);

    }

    //是否可以顯示Canvas的提示
    private boolean isCanShowTips = false;
    //    private boolean isDismiss=false;
    private int interceptCount = 0;//處理兩個控件重疊的攔截

    private boolean needShowEdit = false;

    //三---得到觸摸的控件是哪一個子類,如果兩個控件重疊的話先觸摸到最後添加的
    //不過EditText有點奇怪???
    @Override
    public boolean onTouch(View v, MotionEvent event) {
//        Log.d("zbv", "onTouch   " + ";event action=" + event.getAction());
        //單指觸摸
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
//                Log.d("zbv", "interceptCount=" + interceptCount + ";chihldCount=" + getChildCount());
                //如果存在editText的操作---每次觸摸都會調用縮略圖的更新
                touchFoucusForEditText(false);
                //動態添加移除
                if (interceptCount == 0) {
                    interceptCount++;//1
                    touchView = v;
                    touch_view_left = v.getLeft();
                    touch_view_right = v.getRight();
                    touch_view_top = v.getTop();
                    touch_view_bottom = v.getBottom();
                    touch_view_width = touch_view_right - touch_view_left;
                    touch_view_height = touch_view_bottom - touch_view_top;

                    if (touchView instanceof EditText) {
                        needShowEdit = true;
                    } else {
                        needShowEdit = false;
                    }

                    /*
                    添加遮罩層
                    因爲是觸摸到才添加所以第一觸摸的事件無效-所以出現bug是第一次無法觸摸拖動,
                    因爲遮罩層是最後一個控件所以位置是需要所有控件數+1
                     */
//                    addDrawCustomViewWhenTouch(sp_child.getInt("childCount", -1));
                    addDrawCustomViewWhenTouch(childCount);

                    if (touchView instanceof TextView || touchView instanceof EditText) {
                        QZXTools.logE("zbv", "觸摸到文本視圖", null);
                        thumbnailInterface.touchTextView((TextView) touchView);
                    } else {
                        thumbnailInterface.touchTextView(null);
                    }
                }

//                Log.d("zbv", "touch_width="+touch_view_width+";touch_height=" +touch_view_height
//                                +";touch_left="+touch_view_left+";touch_top="+touch_view_top
//                                +";touch_right="+touch_view_right+";touch_bottom="+touch_view_bottom
//                                +";getX="+event.getX()+";getY="+event.getY());

                break;
            //----想通過動態修改customBGView的onTouchEvent攔截--->不行-因爲一旦修改了就變不回來了
//                Log.d("zbv","interceptCount="+interceptCount);
//                if(isDismiss){
//                    interceptCount=0;
//                    touchView=null;
//                    touch_view_left=0;
//                    touch_view_top=0;
//                    touch_view_right=0;
//                    touch_view_bottom=0;
//                    touch_view_width=0;
//                    touch_view_height=0;
//                    cus_view.transmitParams(0,touch_view_left,touch_view_top,touch_view_width,touch_view_height);
//                    cus_view.updateView(false);
//                }else{
//                    //觸碰到第二個視圖纔是用戶真正想要操作的對象
//                    if(interceptCount==1){
//                        touchView=v;
//                        touch_view_left=v.getLeft();
//                        touch_view_right=v.getRight();
//                        touch_view_top=v.getTop();
//                        touch_view_bottom=v.getBottom();
//                        touch_view_width=touch_view_right-touch_view_left;
//                        touch_view_height=touch_view_bottom-touch_view_top;
//
//                        cus_view.transmitParams(0,touch_view_left,touch_view_top,touch_view_width,touch_view_height);
//
//                        cus_view.updateView(true);
//
//                        Log.d("zbv", "touch_width="+touch_view_width+";touch_height=" +touch_view_height
//                                +";touch_left="+touch_view_left+";touch_top="+touch_view_top
//                                +";touch_right="+touch_view_right+";touch_bottom="+touch_view_bottom
//                                +";getX="+event.getX()+";getY="+event.getY());
//                    }
//                }
//                interceptCount++;
            //--------------------------------------------------
        }


        return false;
    }

    //主動添加孩子的位置和順序號
    public void getChildLocation(int[] location, int position, int degree) {
        //因爲我是先設置這個位置然後再添加給父類所以SparseArray的實例化要在這裏開始
        if (child_sarray == null) {
            child_sarray = new SparseArray<int[]>();
        }
//        QZXTools.logE("zbv", "position=" + position, null);
        child_sarray.put(position, location);
        //角度
        if (degree_sarray == null) {
            degree_sarray = new SparseArray<Integer>();
        }
        if (degree_sarray.get(position) == null) {
            degree_sarray.put(position, degree);
        }
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        //觸摸的那個視圖倒數第二個繪製---因爲我加了一個控制層視圖
        if (touchView != null) {
//            QZXTools.logE("zbv", "touchview--->id" + touchView.getId(), null);
            int position = touchView.getId();
            //想要最後繪製的視圖
            if (i == (position - 1)) {
                return childCount - 2;
            }
            //原本最後繪製的視圖
            else if (i == (childCount - 2)) {
                return position - 1;
            }
        }
        return super.getChildDrawingOrder(childCount, i);
    }

    /**
     * 當觸摸到視圖時爲其添加自定義外圍視圖
     * 觸摸點的位置,寬高,旋轉角度
     */
    private void addDrawCustomViewWhenTouch(int position) {

        QZXTools.logE("zbv", "addDrawCustomViewWhenTouch", null);

        cus_view = new CustomBGView(mContext);
        cus_view.setCustomInterface(this);

        //設置是否僅僅支持移動操作
        cus_view.setOnlyCanMove(isShowActivtiy);

        getChildLocation(new int[]{0, 0}, position, 0);
//        //如果不先賦值會空指針---不用了,改爲一開始就需要設置角度
//        if (degree_sarray == null) {
//            degree_sarray = new SparseArray<Integer>();
//        }
//        if (degree_sarray.get(touchView.getId()) == null) {
//            degree_sarray.put(touchView.getId(), 0);
//        }

//        Log.d("zbv", "position=" + position + ";touchview id=" + touchView.getId());
        int id = touchView.getId();
        cus_view.setDegree(degree_sarray.get(id - 1));

        cus_view.setTouch_x(touch_view_left);
        cus_view.setTouch_y(touch_view_top);
        cus_view.setTouch_width(touch_view_width);
        cus_view.setTouch_height(touch_view_height);

        //是否需要顯示編輯提示---當存在EditText控件時
        cus_view.setNeedShowEdit(needShowEdit);

        ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        addView(cus_view, lp);

    }

    /**
     * 當沒有觸碰到視圖的時候移除
     */
    private void removeDrawCustomViewWhenTouch() {
        removeView(cus_view);
    }

    /**
     * 回調的去除BG
     */
    @Override
    public void dismisssDraw() {
//        Log.d("zbv", "dismissDraw");
        interceptCount = 0;
        removeDrawCustomViewWhenTouch();
    }

    //VP當前頁的ID
    private int curVPPage;

    /**
     * 傳入正在操作的是ViewPager的那一頁---每次VP更新都需要重置
     * 放在Adapter中傳遞,每次instantiate
     */
    public void translateVPPage(int page) {
        curVPPage = page;
    }

    //------------------------------------------------------------------------------
//    private boolean isBackOrGo = false;//是否是撤銷或者前進操作

//    public void setBackOrGo(boolean backOrGo) {
//        isBackOrGo = backOrGo;
//    }

    //如何知道上次是什麼操作???現在的問題是:我保存的數據是原始的,但是操作卻是當前的
    //-------------------------操作更新-------------------------------------------------
    @Override
    public void updateViewMoveLocation(int x, int y) {
//        Log.d("zbv", "x=" + x + ";y=" + y + ";touchID=" + touchView.getId()+";curVPPage="+curVPPage);

        int index = touchView.getId();
        //重置SparseArray的值
        child_sarray.setValueAt(index - 1, new int[]{x, y});

        MarginLayoutParams layoutParams = (MarginLayoutParams) touchView.getLayoutParams();
        //這兩個margin必須要設置的不然高度小於其實繪製的點就看不見了
        layoutParams.leftMargin = (int) x;
        layoutParams.topMargin = (int) y;

        requestLayout();
        invalidate();

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);


        String transText = null;
        if (touchView instanceof TextView || touchView instanceof EditText) {
            transText = ((TextView) touchView).getText().toString();
        }
        OperationRecord operationRecord = new OperationRecord(true, curVPPage, touchView, TRANSLATE, touchView.getId(),
                degree_sarray.get(index - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);

        OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, touchView, TRANSLATE, touchView.getId(),
                degree_sarray.get(index - 1), x, y, touch_view_width, touch_view_height, transText);
        //不是撤銷前進操作就需要記錄操作
//        if (!isBackOrGo) {
        Log.d("zbv", "operation=" + operationRecord);
        thumbnailInterface.saveOperation(operationRecord, operationRecord_new);


        thumbnailInterface.saveNewOperation(operationRecord_new);

//        }


//        //爲什麼不可以
//        touchView.layout(x,y,x+touch_view_width,y+touch_view_height);
//        invalidate();
        //動畫

//        TranslateAnimation translateAnimation=new TranslateAnimation(
//                Animation.RELATIVE_TO_SELF, 0,
//                Animation.RELATIVE_TO_SELF, 200,
//                Animation.RELATIVE_TO_SELF, 0,
//                Animation.RELATIVE_TO_SELF,0);
//        translateAnimation.setDuration(200);
//        translateAnimation.setFillAfter(true);
//        touchView.startAnimation(translateAnimation);
    }


    @Override
    public void updateViewScaleLocation(int x, int y, int right, int bottom) {
        Log.d("zbv", "x=" + x + ";y=" + y + ";right=" + right + ";bottom=" + bottom + ";touchID=" + touchView.getId());
        int index = touchView.getId();
        //重置SparseArray的值
        child_sarray.setValueAt(index - 1, new int[]{x, y});

        MarginLayoutParams layoutParams = (MarginLayoutParams) touchView.getLayoutParams();
        //這兩個margin必須要設置的不然高度小於其實繪製的點就看不見了
        layoutParams.leftMargin = (int) x;
        layoutParams.topMargin = (int) y;

        //改變縮放的寬高
        layoutParams.width = right - x;
        layoutParams.height = bottom - y;

        requestLayout();
        invalidate();

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);

        String transText = null;
        if (touchView instanceof TextView || touchView instanceof EditText) {
            transText = ((TextView) touchView).getText().toString();
        }
        OperationRecord operationRecord = new OperationRecord(true, curVPPage, touchView, SCALE, touchView.getId(),
                degree_sarray.get(index - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);

        OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, touchView, SCALE, touchView.getId(),
                degree_sarray.get(index - 1), x, y, right - x, bottom - y, transText);
        //不是撤銷前進操作就需要記錄操作
//        if (!isBackOrGo) {

        Log.d("zbv", "operation=" + operationRecord);
        thumbnailInterface.saveOperation(operationRecord, operationRecord_new);


        thumbnailInterface.saveNewOperation(operationRecord_new);


//        }


    }

    private int beforeDegree;

    @Override
    public void updateViewRotateLocation(int degree) {

        int id = touchView.getId();
        beforeDegree = degree_sarray.get(id - 1);
        //存儲角度
        degree_sarray.put(id - 1, degree);

        ValueAnimator valueAnimator = ValueAnimator.ofFloat(beforeDegree, degree);
        valueAnimator.setDuration(500);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                touchView.setRotation((float) animation.getAnimatedValue());

            }
        });

        valueAnimator.start();
//        touchView.setRotation(degree);
        invalidate();

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 700);


        String transText = null;
        if (touchView instanceof TextView || touchView instanceof EditText) {
            transText = ((TextView) touchView).getText().toString();
        }
        OperationRecord operationRecord = new OperationRecord(true, curVPPage, touchView, ROTATE, touchView.getId(),
                beforeDegree, touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);

        OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, touchView, ROTATE, touchView.getId(),
                degree_sarray.get(id - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);
        //不是撤銷前進操作就需要記錄操作
//        if (!isBackOrGo) {
        thumbnailInterface.saveOperation(operationRecord, operationRecord_new);


        thumbnailInterface.saveNewOperation(operationRecord_new);


//        }


    }

    private EditText editText;

    @Override
    public void touchFoucusForEditText(boolean isFocus) {
        if (touchView instanceof EditText) {
            Log.d("zbv", "touchVeiw is equal to editText " + isFocus);
            editText = (EditText) touchView;

            editText.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {

                }

                @Override
                public void afterTextChanged(Editable s) {

                    int index = touchView.getId();
                    OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, touchView, EDITMODE, index,
                            degree_sarray.get(index - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, s.toString());
                    thumbnailInterface.saveNewOperation(operationRecord_new);

                }
            });

            editText.setFocusableInTouchMode(isFocus);
            editText.setFocusable(isFocus);
            InputMethodManager methodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
            if (isFocus) {
                //彈出軟鍵盤
                editText.requestFocus();
                methodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
            } else {
                //不可焦且取消軟鍵盤
                methodManager.hideSoftInputFromWindow(getWindowToken(), 0);
            }
        } else {
            if (editText != null) {
                editText.setFocusable(false);
                editText.setFocusableInTouchMode(false);
            }
        }

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);

    }

    //拷貝複製不進行撤銷和回退
    @Override
    public void copyOnceView() {
        if (touchView instanceof TextView) {
            TextView originalTextView = (TextView) touchView;

            TextView tv_one = new TextView(mContext);
            tv_one.setText(originalTextView.getText());
            tv_one.setTextColor(originalTextView.getTextColors());
            tv_one.setBackground(originalTextView.getBackground());
            //爲所要添加的視圖給予一個其所在父類的佈局參數
            ViewGroup.MarginLayoutParams lp_one = new ViewGroup.MarginLayoutParams(
                    originalTextView.getWidth(), originalTextView.getHeight());
            int[] location_one = new int[]{originalTextView.getLeft(), originalTextView.getTop()};
            QZXTools.logE("zbv", "childCount=" + childCount, null);
            //編號從零開始
//            getChildLocation(location_one, sp_child.getInt("childCount", -1));
            getChildLocation(location_one, childCount, 0);
            //設置初始在Layout中的位置
            lp_one.setMargins(location_one[0], location_one[1], 0, 0);
            //如果不添加index默認是-1添加到最後
            addView(tv_one, lp_one);


            String transText = null;
            if (tv_one instanceof TextView || tv_one instanceof EditText) {
                transText = ((TextView) tv_one).getText().toString();
            }
//            OperationRecord operationRecord = new OperationRecord(true, curVPPage, tv_one, COPY, tv_one.getId(),
//                    degree_sarray.get(childCount), location_one[0], location_one[1], lp_one.width, lp_one.height, transText);
//
            OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, originalTextView, COPY,
                    originalTextView.getId(), degree_sarray.get(childCount),
                    location_one[0], location_one[1], lp_one.width, lp_one.height, transText);
            //設置拷貝的視圖類型
            operationRecord_new.setType(type);
            //            //不是撤銷前進操作就需要記錄操作
////            if (!isBackOrGo) {
//            thumbnailInterface.saveOperation(operationRecord,operationRecord_new);


            thumbnailInterface.saveNewOperation(operationRecord_new);


//        }


            //視圖增加一
//            sp_child.edit().putInt("childCount", sp_child.getInt("childCount", -1) + 1).commit();
            childCount++;


        } else if (touchView instanceof EditText) {

        } else if (touchView instanceof ImageView) {

        }

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);

    }

    @Override
    public void deleteOnceView() {
        int id = touchView.getId();
        if (touchView instanceof TextView) {

            removeView(touchView);
            childCount--;

            String transText = null;
            if (touchView instanceof TextView || touchView instanceof EditText) {
                transText = ((TextView) touchView).getText().toString();
            }
//            OperationRecord operationRecord = new OperationRecord(true, curVPPage, touchView, DEL, touchView.getId(),
//                    degree_sarray.get(id - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);
//
            OperationRecord operationRecord_new = new OperationRecord(true, curVPPage, touchView, DEL, touchView.getId(),
                    degree_sarray.get(id - 1), touch_view_left, touch_view_top, touch_view_width, touch_view_height, transText);
//            //不是撤銷前進操作就需要記錄操作
////            if (!isBackOrGo) {
//            thumbnailInterface.saveOperation(operationRecord,operationRecord_new);


            thumbnailInterface.saveNewOperation(operationRecord_new);


//        }


            //注意的是:所有大於該視圖編號的要重排
            child_sarray.removeAt(touchView.getId());
            degree_sarray.removeAt(touchView.getId());

        } else if (touchView instanceof EditText) {

        } else if (touchView instanceof ImageView) {

        }

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);

    }

//    //一下三個方法用於撤銷和回退以及文本返回的----不可取重新new了新的對象
//    public void cancelDelView(View cancleView) {
//
//        if (cancleView instanceof TextView) {
//
//            TextView tv_one = new TextView(mContext);
//            tv_one.setText("七子笑");
//            tv_one.setTextColor(Color.WHITE);
//            tv_one.setBackgroundColor(Color.BLACK);
//            //爲所要添加的視圖給予一個其所在父類的佈局參數
//            ViewGroup.MarginLayoutParams lp_one = new ViewGroup.MarginLayoutParams(300, 200);
//            int[] location_one = new int[]{100, 200};
//            //編號從零開始
////            getChildLocation(location_one, sp_child.getInt("childCount", -1));
//
//            getChildLocation(location_one, childCount, 0);
//            //設置初始在Layout中的位置
//            lp_one.setMargins(location_one[0], location_one[1], 0, 0);
//            //如果不添加index默認是-1添加到最後
//            addView(tv_one, lp_one);
//
//            //視圖增加一
////            sp_child.edit().putInt("childCount", sp_child.getInt("childCount", -1) + 1).commit();
//            childCount++;
//
//        } else if (cancleView instanceof EditText) {
//
//        } else if (cancleView instanceof ImageView) {
//
//        }
//        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
//        postDelayed(new Runnable() {
//            @Override
//            public void run() {
//                thumbnailInterface.notifyLayoutChange();
//            }
//        }, 200);
//
//    }
//
//    public void cancleCopyView(View cancleView) {
//        if (cancleView instanceof TextView) {
//
//            removeView(cancleView);
//            childCount--;
//
//            //注意的是:所有大於該視圖編號的要重排
//            child_sarray.removeAt(cancleView.getId());
//            degree_sarray.removeAt(cancleView.getId());
//
//        } else if (cancleView instanceof EditText) {
//
//        } else if (cancleView instanceof ImageView) {
//
//        }
//
//        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
//        postDelayed(new Runnable() {
//            @Override
//            public void run() {
//                thumbnailInterface.notifyLayoutChange();
//            }
//        }, 200);
//    }

    /**
     * 針對複製和刪除的操作不能new一個新的對象,而是要對之前的對象進行操作
     */
    public void updateOperation(int x, int y, int right, int bottom, int degree, boolean isCopy, boolean isDel, boolean isBack) {

        int index = touchView.getId();
        //重置SparseArray的值
        child_sarray.setValueAt(index - 1, new int[]{x, y});

        beforeDegree = degree_sarray.get(index - 1);
        //存儲角度
        degree_sarray.put(index - 1, degree);

        MarginLayoutParams layoutParams = (MarginLayoutParams) touchView.getLayoutParams();
        //這兩個margin必須要設置的不然高度小於其實繪製的點就看不見了
        layoutParams.leftMargin = (int) x;
        layoutParams.topMargin = (int) y;

        //改變縮放的寬高
        layoutParams.width = right - x;
        layoutParams.height = bottom - y;

        touchView.setRotation(degree);

//        if(isCopy){
//            if(isBack){
//                removeView(touchView);
//            }else{
//                addView(touchView);
//            }
//        }else if(isDel){
//            if(isBack){
//                addView(touchView);
//            }else{
//                removeView(touchView);
//            }
//        }

        requestLayout();
        invalidate();

        //延遲200ms這個時間可以依據實際調節,立即調用的話layout沒有繪製完全
        postDelayed(new Runnable() {
            @Override
            public void run() {
                thumbnailInterface.notifyLayoutChange();
            }
        }, 200);
    }


    //---------------------------操作更新-----------------------------------------------

    //---------------------------記錄保存---------------------------------------------

//    /**
//     * 操作記錄保存
//     */
//    private void operationSave(int x, int y, int right, int bottom) {
//
//    }
    //---------------------------記錄保存---------------------------------------------

//    @Override
//    public boolean onScale(ScaleGestureDetector detector) {
//        float scaleFactor=detector.getScaleFactor();
//        Log.d("zbv","scaleFactor="+scaleFactor);
//        setScaleX(scaleFactor);
//        setScaleY(scaleFactor);
//        return true;
//    }
//
//    @Override
//    public boolean onScaleBegin(ScaleGestureDetector detector) {
//        return true;
//    }
//
//    @Override
//    public void onScaleEnd(ScaleGestureDetector detector) {
//
//    }

    //提供接口和Activity交互
    private ThumbnailInterface thumbnailInterface;

    public void setThumbnailInterface(ThumbnailInterface thumbnailInterface) {
        this.thumbnailInterface = thumbnailInterface;
    }

    public interface ThumbnailInterface {
        /**
         * 加載完畢和佈局改變都一樣
         */
        void notifyLayoutChange();

        /**
         * 操作記錄保存
         */
        void saveOperation(OperationRecord operationRecord, OperationRecord newOperationRecord);

        /**
         * 保存最新的操作---用於json的數據實時保存
         */
        void saveNewOperation(OperationRecord operationRecord);

        /**
         * 觸摸到的是文本視圖:TextView或者EditText
         * <br/><br/>
         * 如果觸摸的不是文本類就置空null
         */
        void touchTextView(TextView textView);

    }
}

2、遮罩層CustomBGView

package com.ahtelit.zbv.vphandler;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2018/4/27.
 * qzx
 * <p>
 * Match_Parent Match_Parent
 */

public class CustomBGView extends View {

    //設置僅僅可以移動操作標誌
    private boolean isOnlyCanMove = false;

    public void setOnlyCanMove(boolean onlyCanMove) {
        isOnlyCanMove = onlyCanMove;
    }

    private Paint mPaint;

    //在添加給Layout時需要預先設置--------------
    private int degree;
    private float touch_x;
    private float touch_y;
    private float touch_right;
    private float touch_bottom;
    private int touch_width;
    private int touch_height;

    public float getDegree() {
        return degree;
    }

    public void setDegree(int degree) {
        this.degree = degree;
    }

    public float getTouch_x() {
        return touch_x;
    }

    public void setTouch_x(float touch_x) {
        this.touch_x = touch_x;
    }

    public float getTouch_y() {
        return touch_y;
    }

    public void setTouch_y(float touch_y) {
        this.touch_y = touch_y;
    }

    public int getTouch_width() {
        return touch_width;
    }

    //必須在設置了touch_x後
    public void setTouch_width(int touch_width) {
        this.touch_width = touch_width;
//        if(degree!=0){
//            touch_right= (float) (touch_x+touch_width*Math.cos(Math.toRadians(degree)));
//        }else{
        touch_right = touch_x + touch_width;
//        }
    }

    public int getTouch_height() {
        return touch_height;
    }

    //必須在設置了touch_後
    public void setTouch_height(int touch_height) {
        this.touch_height = touch_height;
//        if(degree!=0){
//            touch_bottom= (float) (touch_x+touch_height*Math.cos(Math.toRadians(degree)));
//        }else{
        touch_bottom = touch_y + touch_height;
//        }
    }

//    public void transmitParams(int deg,float x,float y,int width,int height){
//        degree=deg;
//        touch_x=x;
//        touch_y=y;
//        touch_width=width;
//        touch_height=height;
//    }

    //------------------------------------------------

    public void updateView() {
        invalidate();
    }

    //----------------------------------------------
    public CustomBGView(Context context) {
        this(context, null);
    }

    public CustomBGView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomBGView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        rotate_rect = new Rect();
        copy_rect = new Rect();
        edit_rect = new Rect();
        del_rect = new Rect();
        line_rect = new Rect();

        effect = new DashPathEffect(new float[]{20, 5}, 0);
    }

    private static final float CIRCLE_RADIUS = 20;
    private static final int INTERVAL = 90;
    private float TIPS_WIDTH = 200;
    private static final int TIPS_HEIGHT = 60;
    private static final float TEXT_SIZE = 30;

    //    private static final float TIPS_INTERVAL=40;//每個字體佔用的空間
    private static final float TIPS_DIVIDE = 10;//豎線的間隔

    private static final String TEXT_ROTATE = "旋轉";
    private static final String TEXT_COPY = "複製";
    private static final String TEXT_EDIT = "編輯";
    private static final String TEXT_DEL = "刪除";
    private static final String TEXT_LINE = "|";

//    //操控音樂盒視頻
//    private static final String TEXT_OPERATE_MUSIC = "操控音樂";
//    private static final String TEXT_OPERATE_VIDEO = "操控視頻";

    //    private int degree_rotate = 0;//顯示角度提示
    private Rect rotate_rect, copy_rect, edit_rect, del_rect, line_rect;

    private DashPathEffect effect;//波折線
    private static final int LineTouchW = 70;

    private static final int STROKE_WIDTH = 7;

    //因爲是全屏的
    @Override
    protected void onDraw(Canvas canvas) {
//        Log.d("zbv", "isCanMove=" + isCanMove + ";isCanScale=" + isCanScale + ";isCanRotate=" + isCanRotate + ";rotate_degree=" + degree);
        if (!isCanMove && !isCanScale && !isCanRotate) {

            if (isOnlyCanMove) {

                mPaint.setColor(Color.GREEN);

                mPaint.setStyle(Paint.Style.STROKE);

                mPaint.setStrokeWidth(STROKE_WIDTH);

                canvas.drawRect(touch_x, touch_y, touch_x + touch_width, touch_y + touch_height, mPaint);


            } else {
                if (degree != 0) {
                    canvas.save();
                    canvas.rotate(degree, touch_x + touch_width / 2, touch_y + touch_height / 2);

                    //可縮放的紅點區域
                    mPaint.setColor(Color.RED);
                    canvas.drawCircle(touch_x, touch_y, CIRCLE_RADIUS, mPaint);//左上
                    canvas.drawCircle(touch_x + touch_width, touch_y, CIRCLE_RADIUS, mPaint);//右上
                    canvas.drawCircle(touch_x, touch_y + touch_height, CIRCLE_RADIUS, mPaint);//左下
                    canvas.drawCircle(touch_x + touch_width, touch_y + touch_height, CIRCLE_RADIUS, mPaint);//右下


                    //是否顯示可編輯-在有EditText視圖下顯示
                    if (isNeedShowEdit) {
                        //重置tips的寬度
                        TIPS_WIDTH = 320;
                        //提示操作區域
                        mPaint.setColor(Color.GRAY);
                        //左邊+參考寬度的一半-所畫矩形寬度的一半
                        canvas.drawRect(touch_x + touch_width / 2 - TIPS_WIDTH / 2, touch_y - INTERVAL - TIPS_HEIGHT, touch_x + touch_width / 2 + TIPS_WIDTH / 2, touch_y - INTERVAL, mPaint);
                        mPaint.setColor(Color.WHITE);
                        mPaint.setTextSize(TEXT_SIZE);
                        //文本居中對齊
                        mPaint.setTextAlign(Paint.Align.CENTER);
                        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                        //需要計算一番,讓文字在矩形背景的中間
                        float baseLine = touch_y - INTERVAL + (fontMetrics.top - fontMetrics.bottom) / 2;

                        mPaint.getTextBounds(TEXT_ROTATE, 0, TEXT_ROTATE.length(), rotate_rect);
                        mPaint.getTextBounds(TEXT_COPY, 0, TEXT_COPY.length(), copy_rect);
                        mPaint.getTextBounds(TEXT_EDIT, 0, TEXT_EDIT.length(), edit_rect);
                        mPaint.getTextBounds(TEXT_LINE, 0, TEXT_LINE.length(), line_rect);
                        mPaint.getTextBounds(TEXT_DEL, 0, TEXT_DEL.length(), del_rect);

                        //因爲align是center所以只要自己的一半算進去就可以了,其他的原來多長就算多長
//                    canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() / 2 - TIPS_DIVIDE * 2 - line_rect.width(), baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE - line_rect.width() / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_COPY, touch_x + touch_width / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE + line_rect.width() / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_EDIT, touch_x + touch_width / 2 + edit_rect.width() / 2 + copy_rect.width() / 2 + TIPS_DIVIDE * 2, baseLine, mPaint);

                        canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() - TIPS_DIVIDE * 3 - line_rect.width(), baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() - TIPS_DIVIDE * 2 - line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_COPY, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2, baseLine, mPaint);//中心
                        canvas.drawText(TEXT_EDIT, touch_x + touch_width / 2 + edit_rect.width() / 2 + TIPS_DIVIDE, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + edit_rect.width() + TIPS_DIVIDE * 2 + line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_DEL, touch_x + touch_width / 2 + del_rect.width() / 2 + edit_rect.width() + TIPS_DIVIDE * 3 + line_rect.width(), baseLine, mPaint);
                    } else {
                        //重置tips的寬度
                        TIPS_WIDTH = 240;
                        //提示操作區域
                        mPaint.setColor(Color.GRAY);
                        //左邊+參考寬度的一半-所畫矩形寬度的一半
                        canvas.drawRect(touch_x + touch_width / 2 - TIPS_WIDTH / 2, touch_y - INTERVAL - TIPS_HEIGHT, touch_x + touch_width / 2 + TIPS_WIDTH / 2, touch_y - INTERVAL, mPaint);
                        mPaint.setColor(Color.WHITE);
                        mPaint.setTextSize(TEXT_SIZE);
                        //文本居中對齊
                        mPaint.setTextAlign(Paint.Align.CENTER);
                        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                        //需要計算一番,讓文字在矩形背景的中間
                        float baseLine = touch_y - INTERVAL + (fontMetrics.top - fontMetrics.bottom) / 2;

                        mPaint.getTextBounds(TEXT_ROTATE, 0, TEXT_ROTATE.length(), rotate_rect);
                        mPaint.getTextBounds(TEXT_COPY, 0, TEXT_COPY.length(), copy_rect);
                        mPaint.getTextBounds(TEXT_EDIT, 0, TEXT_EDIT.length(), edit_rect);
                        mPaint.getTextBounds(TEXT_DEL, 0, TEXT_DEL.length(), del_rect);

//                    canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - TIPS_DIVIDE, baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_COPY, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE, baseLine, mPaint);

                        canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() / 2 - TIPS_DIVIDE * 2 - line_rect.width(), baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE - line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_COPY, touch_x + touch_width / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE + line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_DEL, touch_x + touch_width / 2 + del_rect.width() / 2 + copy_rect.width() / 2 + TIPS_DIVIDE * 2, baseLine, mPaint);
                    }

                    canvas.restore();

                } else {
                    //可縮放的紅點區域
                    mPaint.setColor(Color.RED);
                    canvas.drawCircle(touch_x, touch_y, CIRCLE_RADIUS, mPaint);//左上
                    canvas.drawCircle(touch_x + touch_width, touch_y, CIRCLE_RADIUS, mPaint);//右上
                    canvas.drawCircle(touch_x, touch_y + touch_height, CIRCLE_RADIUS, mPaint);//左下
                    canvas.drawCircle(touch_x + touch_width, touch_y + touch_height, CIRCLE_RADIUS, mPaint);//右下


                    //是否顯示可編輯-在有EditText視圖下顯示
                    if (isNeedShowEdit) {
                        //重置tips的寬度
                        TIPS_WIDTH = 320;
                        //提示操作區域
                        mPaint.setColor(Color.GRAY);
                        //左邊+參考寬度的一半-所畫矩形寬度的一半
                        canvas.drawRect(touch_x + touch_width / 2 - TIPS_WIDTH / 2, touch_y - INTERVAL - TIPS_HEIGHT, touch_x + touch_width / 2 + TIPS_WIDTH / 2, touch_y - INTERVAL, mPaint);
                        mPaint.setColor(Color.WHITE);
                        mPaint.setTextSize(TEXT_SIZE);
                        //文本居中對齊
                        mPaint.setTextAlign(Paint.Align.CENTER);
                        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                        //需要計算一番,讓文字在矩形背景的中間
                        float baseLine = touch_y - INTERVAL + (fontMetrics.top - fontMetrics.bottom) / 2;

                        mPaint.getTextBounds(TEXT_ROTATE, 0, TEXT_ROTATE.length(), rotate_rect);
                        mPaint.getTextBounds(TEXT_COPY, 0, TEXT_COPY.length(), copy_rect);
                        mPaint.getTextBounds(TEXT_EDIT, 0, TEXT_EDIT.length(), edit_rect);
                        mPaint.getTextBounds(TEXT_LINE, 0, TEXT_LINE.length(), line_rect);
                        mPaint.getTextBounds(TEXT_DEL, 0, TEXT_DEL.length(), del_rect);

                        //因爲align是center所以只要自己的一半算進去就可以了,其他的原來多長就算多長
//                    canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() / 2 - TIPS_DIVIDE * 2 - line_rect.width(), baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE - line_rect.width() / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_COPY, touch_x + touch_width / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE + line_rect.width() / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_EDIT, touch_x + touch_width / 2 + edit_rect.width() / 2 + copy_rect.width() / 2 + TIPS_DIVIDE * 2, baseLine, mPaint);

                        canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() - TIPS_DIVIDE * 3 - line_rect.width(), baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() - TIPS_DIVIDE * 2 - line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_COPY, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2, baseLine, mPaint);//中心
                        canvas.drawText(TEXT_EDIT, touch_x + touch_width / 2 + edit_rect.width() / 2 + TIPS_DIVIDE, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + edit_rect.width() + TIPS_DIVIDE * 2 + line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_DEL, touch_x + touch_width / 2 + del_rect.width() / 2 + edit_rect.width() + TIPS_DIVIDE * 3 + line_rect.width(), baseLine, mPaint);
                    } else {
                        //重置tips的寬度
                        TIPS_WIDTH = 240;
                        //提示操作區域
                        mPaint.setColor(Color.GRAY);
                        //左邊+參考寬度的一半-所畫矩形寬度的一半
                        canvas.drawRect(touch_x + touch_width / 2 - TIPS_WIDTH / 2, touch_y - INTERVAL - TIPS_HEIGHT, touch_x + touch_width / 2 + TIPS_WIDTH / 2, touch_y - INTERVAL, mPaint);
                        mPaint.setColor(Color.WHITE);
                        mPaint.setTextSize(TEXT_SIZE);
                        //文本居中對齊
                        mPaint.setTextAlign(Paint.Align.CENTER);
                        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                        //需要計算一番,讓文字在矩形背景的中間
                        float baseLine = touch_y - INTERVAL + (fontMetrics.top - fontMetrics.bottom) / 2;

                        mPaint.getTextBounds(TEXT_ROTATE, 0, TEXT_ROTATE.length(), rotate_rect);
                        mPaint.getTextBounds(TEXT_COPY, 0, TEXT_COPY.length(), copy_rect);
                        mPaint.getTextBounds(TEXT_EDIT, 0, TEXT_EDIT.length(), edit_rect);
                        mPaint.getTextBounds(TEXT_DEL, 0, TEXT_DEL.length(), del_rect);

//                    canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - TIPS_DIVIDE, baseLine, mPaint);
//                    canvas.drawText(TEXT_LINE, touch_x + touch_width / 2, baseLine, mPaint);
//                    canvas.drawText(TEXT_COPY, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE, baseLine, mPaint);

                        canvas.drawText(TEXT_ROTATE, touch_x + touch_width / 2 - rotate_rect.width() / 2 - copy_rect.width() / 2 - TIPS_DIVIDE * 2 - line_rect.width(), baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 - copy_rect.width() / 2 - TIPS_DIVIDE - line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_COPY, touch_x + touch_width / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_LINE, touch_x + touch_width / 2 + copy_rect.width() / 2 + TIPS_DIVIDE + line_rect.width() / 2, baseLine, mPaint);
                        canvas.drawText(TEXT_DEL, touch_x + touch_width / 2 + del_rect.width() / 2 + copy_rect.width() / 2 + TIPS_DIVIDE * 2, baseLine, mPaint);
                    }
                }
            }
        }

        mPaint.setColor(0x70cccccc);

        //如果是演示層重置會實體繪製
        mPaint.setStyle(Paint.Style.FILL);

        if (isCanMove) {
            if (degree != 0) {
                canvas.save();
                canvas.rotate(degree, touch_x + touch_width / 2, touch_y + touch_height / 2);
                canvas.drawRect(touch_x, touch_y, touch_x + touch_width, touch_y + touch_height, mPaint);
                canvas.restore();
            } else {
                //要做變換的矩形
                canvas.drawRect(touch_x, touch_y, touch_x + touch_width, touch_y + touch_height, mPaint);
            }

        } else if (isCanScale) {
            if (degree != 0) {
                Log.d("zbv", "縮放有角度旋轉" + degree);
                canvas.save();
                canvas.rotate(degree, touch_x + touch_width / 2, touch_y + touch_height / 2);
                canvas.drawRect(touch_x, touch_y, touch_right, touch_bottom, mPaint);
                canvas.restore();
            } else {
//            Log.d("zbv","touch_right="+touch_right+";touch_bottom="+touch_bottom);
                canvas.drawRect(touch_x, touch_y, touch_right, touch_bottom, mPaint);
            }

        } else if (isNeedRotate || isCanRotate) {
            //黑色背景,白色字跡,灰色旋轉線

            canvas.save();

            canvas.rotate(degree, touch_x + touch_width / 2, touch_y + touch_height / 2);

            //旋轉的矩形
            canvas.drawRect(touch_x, touch_y, touch_x + touch_width, touch_y + touch_height, mPaint);

            TIPS_WIDTH = 70;
            //繪畫可旋轉的視圖
            mPaint.setColor(Color.BLACK);
            canvas.drawRect(touch_x + touch_width / 2 - TIPS_WIDTH / 2, touch_y - INTERVAL - TIPS_HEIGHT, touch_x + touch_width / 2 + TIPS_WIDTH / 2, touch_y - INTERVAL, mPaint);

            mPaint.setColor(Color.WHITE);
            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
            float baseLine = touch_y - INTERVAL + (fontMetrics.top - fontMetrics.bottom) / 2;
            canvas.drawText(degree + "°", touch_x + touch_width / 2, baseLine, mPaint);

            //虛線
            mPaint.setColor(Color.GRAY);
            mPaint.setPathEffect(effect);
            canvas.drawLine(touch_x + touch_width / 2, touch_y, touch_x + touch_width / 2, touch_y - INTERVAL, mPaint);

            canvas.restore();

        }


    }

    //記錄觸摸下的down座標
    private float downX;
    private float downY;
    private boolean isCanMove;
    private boolean isCanScale;
    private boolean isCanCopy;//拷貝對象
    private boolean isCanDelete;//刪除對象
//    private boolean isCanEdit;

    private boolean isCanRotate;
    private boolean isNeedRotate;

    private String scaleText;
    private static final float MIN_WIDTH = 100;

    private boolean isNeedShowEdit = false;//是否需要顯示編輯

    public void setNeedShowEdit(boolean needShowEdit) {
        isNeedShowEdit = needShowEdit;
    }

    private float scaleDownX;
    private float scaleDonwY;


    /**
     * 由這個自定義背景視圖來處理操作給予反饋
     * 如果第一次返回false之後再也接受不到了
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
//        Log.d("zbv", "customView onTouchEvent" + event.getAction());
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (isOnlyCanMove) {
                    downX = event.getX();
                    downY = event.getY();
                    if (downX < touch_x || downX > (touch_x + touch_width)
                            || downY < touch_y || downY > (touch_y + touch_height)) {
                        isCanMove = false;
                        //需要傳遞觸摸事件
                        customInterface.dismisssDraw();
                        return false;
                    } else {
                        isCanMove = true;
                    }
                } else {
                    //使用downX和downY
                    scaleDownX = event.getX();
                    scaleDonwY = event.getY();
                    if (degree != 0) {
                        Log.d("zbv", "右旋轉角=" + degree);
                        float currentLocations[] = getBeforeViewLocation(degree, event.getX(), event.getY());
                        downX = currentLocations[0];
                        downY = currentLocations[1];
                    } else {
                        downX = event.getX();
                        downY = event.getY();
                    }
                    if (isCanRotate) {
                        //觸摸到旋轉線以外的地方都取消旋轉操作---設置粗一點
                        //增加觸摸提示旋轉角度矩形也可以觸發旋轉
                        if (downX > touch_x + touch_width / 2 - LineTouchW / 2 && downX < touch_x + touch_width / 2 + LineTouchW / 2
                                && downY > touch_y - INTERVAL && downY < touch_y) {
                            Log.d("zbv", "觸摸到旋轉虛線");
                            isNeedRotate = true;
                        } else if (downX > touch_x + touch_width / 2 - TIPS_WIDTH / 2
                                && downX < touch_x + touch_width / 2 + TIPS_WIDTH / 2
                                && downY > touch_y - INTERVAL - TIPS_HEIGHT && downY < touch_y - INTERVAL) {
                            Log.d("zbv", "觸摸到旋轉提示框");
                            isNeedRotate = true;
                        } else {
                            //取消操作
                            customInterface.dismisssDraw();
                        }

                    } else {
                        //如果觸摸到縮放區域-左上 左下 右上 右下
                        if ((downX > touch_x - CIRCLE_RADIUS && downX < touch_x + CIRCLE_RADIUS
                                && downY > touch_y - CIRCLE_RADIUS && downY < touch_y + CIRCLE_RADIUS)) {
                            Log.d("zbv", "觸摸到要縮放的區域了---左上");
                            isCanScale = true;
                            scaleText = "左上";
                            invalidate();
                        } else if (downX > touch_x - CIRCLE_RADIUS && downX < touch_x + CIRCLE_RADIUS
                                && downY > touch_y - CIRCLE_RADIUS + touch_height &&
                                downY < touch_y + CIRCLE_RADIUS + touch_height) {
                            Log.d("zbv", "觸摸到要縮放的區域了---左下");
                            isCanScale = true;
                            scaleText = "左下";
                            invalidate();
                        } else if (downX > touch_x - CIRCLE_RADIUS + touch_width
                                && downX < touch_x + CIRCLE_RADIUS + touch_width
                                && downY > touch_y - CIRCLE_RADIUS && downY < touch_y + CIRCLE_RADIUS) {
                            Log.d("zbv", "觸摸到要縮放的區域了---右上");
                            isCanScale = true;
                            scaleText = "右上";
                            invalidate();
                        } else if (downX > touch_x - CIRCLE_RADIUS + touch_width
                                && downX < touch_x + CIRCLE_RADIUS + touch_width
                                && downY > touch_y - CIRCLE_RADIUS + touch_height
                                && downY < touch_y + CIRCLE_RADIUS + touch_height) {
                            Log.d("zbv", "觸摸到要縮放的區域了---右下");
                            isCanScale = true;
                            scaleText = "右下";
                            invalidate();
                        }
                        //是否觸摸到旋轉區域
                        else if (isNeedShowEdit) {
                            //顯示編輯的旋轉區域---不用修改在邊緣
                            if (downX > touch_x + touch_width / 2 - TIPS_WIDTH / 2 &&
                                    downX < touch_x + touch_width / 2 + rotate_rect.width() - TIPS_WIDTH / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到可編輯的旋轉");
                                isCanRotate = true;
                                invalidate();
                            }
                            //顯示編輯的複製區域
                            else if (downX > touch_x + touch_width / 2 - copy_rect.width() &&
                                    downX < touch_x + touch_width / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到可編輯的複製");
                                isCanCopy = true;
                            }
                            //顯示編輯的編輯區域
                            else if (downX > touch_x + touch_width / 2 &&
                                    downX < touch_x + touch_width / 2 + edit_rect.width() &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到可編輯的編輯");
//                            isCanEdit = true;
                                //可以聚焦
                                customInterface.touchFoucusForEditText(true);

                            }
                            //顯示編輯的刪除區域
                            else if (downX > touch_x + touch_width / 2 + del_rect.width() &&
                                    downX < touch_x + touch_width / 2 + TIPS_WIDTH / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到可編輯的刪除");

                                isCanDelete = true;

                            }
                            //是否觸摸到不操作區域
                            else if (downX < touch_x || downX > (touch_x + touch_width)
                                    || downY < touch_y || downY > (touch_y + touch_height)) {
                                Log.d("zbv", "觸摸到可編輯外邊了");
                                isCanMove = false;

                                //消失不可編輯
//                            isCanEdit=false;
                                customInterface.touchFoucusForEditText(false);

                                //需要傳遞觸摸事件
                                customInterface.dismisssDraw();
                                return false;

                            } else {
                                isCanMove = true;
                            }

                        } else if (!isNeedShowEdit) {
                            //不顯示編輯的旋轉區域
                            if (downX > touch_x + touch_width / 2 - TIPS_WIDTH / 2 &&
                                    downX < touch_x + touch_width / 2 - copy_rect.width() / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到無編輯的旋轉");
                                isCanRotate = true;
                                invalidate();
                            }
                            //不顯示編輯的複製區域
                            else if (downX > touch_x + touch_width / 2 - copy_rect.width() / 2 &&
                                    downX < touch_x + touch_width / 2 + copy_rect.width() / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到無編輯的複製");
                                isCanCopy = true;
                            } else if (downX > touch_x + touch_width / 2 + copy_rect.width() / 2 &&
                                    downX < touch_x + touch_width / 2 + TIPS_WIDTH / 2 &&
                                    downY > touch_y - INTERVAL - TIPS_HEIGHT &&
                                    downY < touch_y - INTERVAL) {
                                Log.d("zbv", "觸摸到無編輯的刪除");
                                isCanDelete = true;
                            }
                            //是否觸摸到不操作區域
                            else if (downX < touch_x || downX > (touch_x + touch_width)
                                    || downY < touch_y || downY > (touch_y + touch_height)) {
                                Log.d("zbv", "觸摸到不可編輯外邊了");
                                isCanMove = false;
                                //需要傳遞觸摸事件
                                customInterface.dismisssDraw();
                                return false;

                            } else {
                                isCanMove = true;
                            }
                        }
                    }
                }

                break;
            case MotionEvent.ACTION_MOVE:

                if (isCanScale) {
                    //----------------可縮放   限制最小縮放大小
                    if (scaleText.equals("左上")) {

                        //top and left

                        //之所以使用原先的觸摸點是因爲旋轉改變了真實的觸摸點,所以要還原
                        touch_x += event.getX() - scaleDownX;
                        touch_y += event.getY() - scaleDonwY;

                        //必須分開,不然注意判斷
                        if (Math.abs(touch_right - touch_x) < MIN_WIDTH) {
                            touch_x = touch_right - MIN_WIDTH;
                        }
                        if (Math.abs(touch_bottom - touch_y) < MIN_WIDTH) {
                            touch_y = touch_bottom - MIN_WIDTH;
                        }

                    } else if (scaleText.equals("左下")) {

                        //bottom and left

                        touch_x += event.getX() - scaleDownX;
                        touch_bottom += event.getY() - scaleDonwY;

                        //必須分開,不然注意判斷
                        if (Math.abs(touch_right - touch_x) < MIN_WIDTH) {
                            touch_x = touch_right - MIN_WIDTH;
                        }
                        if (Math.abs(touch_bottom - touch_y) < MIN_WIDTH) {
                            touch_bottom = touch_y + MIN_WIDTH;
                        }

                    } else if (scaleText.equals("右上")) {

                        //top and right

                        touch_right += event.getX() - scaleDownX;
                        touch_y += event.getY() - scaleDonwY;

                        //必須分開,不然注意判斷
                        if (Math.abs(touch_right - touch_x) < MIN_WIDTH) {
                            touch_right = touch_x + MIN_WIDTH;
                        }
                        if (Math.abs(touch_bottom - touch_y) < MIN_WIDTH) {
                            touch_y = touch_bottom - MIN_WIDTH;
                        }

                    } else if (scaleText.equals("右下")) {

                        //bottom and right

                        touch_right += event.getX() - scaleDownX;
                        touch_bottom += event.getY() - scaleDonwY;

                        //必須分開,不然注意判斷
                        if (Math.abs(touch_right - touch_x) < MIN_WIDTH) {
                            touch_right = touch_x + MIN_WIDTH;
                        }
                        if (Math.abs(touch_bottom - touch_y) < MIN_WIDTH) {
                            touch_bottom = touch_y + MIN_WIDTH;
                        }
                    }

                    invalidate();
                    scaleDownX = event.getX();
                    scaleDonwY = event.getY();


                } else if (isNeedRotate) {
                    //----------------可旋轉
                    //以視圖中心點爲圓心進行旋轉
                    double arc_1 = Math.atan2(downY - (touch_y + touch_height / 2), downX - (touch_x + touch_width / 2));
                    double arc_2 = Math.atan2(event.getY() - (touch_y + touch_height / 2), event.getX() - (touch_x + touch_width / 2));
                    double angle_1 = Math.toDegrees(arc_1);
                    double angle_2 = Math.toDegrees(arc_2);
//                    Log.d("zbv","angle_1="+angle_1+";angle_2="+angle_2);
                    degree = (int) Math.round(angle_2 - angle_1);

                    if (degree > 180.0f) {
                        degree -= 360.0f;
                    }

                    invalidate();

                } else if (isCanMove) {
                    //----------------可移動
                    touch_x = touch_x + event.getX() - downX;
                    touch_y = touch_y + event.getY() - downY;

                    //設置移動邊界防止越界看不見
                    if (touch_x <= 0) {
                        touch_x = 0;
                    } else if (touch_x >= (getWidth() - touch_width)) {
                        touch_x = getWidth() - touch_width;
                    }
                    if (touch_y <= 0) {
                        touch_y = 0;
                    } else if (touch_y >= (getHeight() - touch_height)) {
                        touch_y = getHeight() - touch_height;
                    }

//                    Log.d("zbv","touch_x="+touch_x+";touch_y="+touch_y);

                    invalidate();
                    //必須重置觸摸點
                    downX = event.getX();
                    downY = event.getY();


                }

                break;
            case MotionEvent.ACTION_UP:

                if (isCanRotate) {
                    if (isNeedRotate) {
                        isCanRotate = false;
                        isNeedRotate = false;
                        customInterface.updateViewRotateLocation(degree);
                        //取消bg繪製
                        customInterface.dismisssDraw();
                    }
                } else {
                    //縮放重置
                    if (isCanScale) {
                        isCanScale = false;
                        customInterface.updateViewScaleLocation((int) touch_x, (int) touch_y, (int) touch_right, (int) touch_bottom);
                    }
                    //跟新視圖的移動位置
                    if (isCanMove) {
                        isCanMove = false;
                        customInterface.updateViewMoveLocation((int) touch_x, (int) touch_y);
                    }
                    //取消bg繪製
                    customInterface.dismisssDraw();

                    //執行拷貝
                    if (isCanCopy) {
                        isCanCopy = false;
                        customInterface.copyOnceView();
                    }

                    //執行刪除
                    if (isCanDelete) {
                        isCanDelete = false;
                        customInterface.deleteOnceView();
                    }

                }

                break;

            case MotionEvent.ACTION_POINTER_DOWN:

                break;
            case MotionEvent.ACTION_POINTER_UP:
                break;
        }
        return true;
    }

    /*
  爲了處理canvas旋轉導致的視圖屬性沒有變化從而使得觸摸點的無法生效
  所以反推原始點即:知道圓點、和旋轉後的點以及角度--->推導出旋轉前的點
   */
    private float[] getBeforeViewLocation(float angle, float dot_x, float dot_y) {
        float jiaodu = -angle;
        float[] locations = new float[2];
        double arcValue = Math.toRadians(jiaodu);
        float sin = (float) Math.sin(arcValue);
        float cos = (float) Math.cos(arcValue);
        locations[0] = (dot_x - (touch_x + touch_width / 2)) * cos - (dot_y - (touch_y + touch_height / 2)) * sin + touch_x + touch_width / 2;
        locations[1] = (dot_y - (touch_y + touch_height / 2)) * cos + (dot_x - (touch_x + touch_width / 2)) * sin + touch_y + touch_height / 2;
        return locations;
    }

    //----------------------------
    private CustomInterface customInterface;

    public void setCustomInterface(CustomInterface customInterface) {
        this.customInterface = customInterface;
    }

    public interface CustomInterface {
        void dismisssDraw();

        void updateViewMoveLocation(int x, int y);

        void updateViewScaleLocation(int x, int y, int right, int bottom);

        void updateViewRotateLocation(int degree);

        void touchFoucusForEditText(boolean isFoucus);

        void copyOnceView();

        void deleteOnceView();
    }
}

後續功能增加以及優化、demo例子使用更新中。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章