@Override
  public boolean onTouchEvent(MotionEvent event) {
    boolean handled = true;
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
      case MotionEvent.ACTION_DOWN:
        {
          // 删除按钮接收事件
          if (mShowDashBorder && mDelDrawRectF.contains(event.getX(), event.getY())) {
            if (getParent() instanceof ViewGroup) {
              ((ViewGroup) getParent()).removeView(DashFrameLayout.this);
            }
            break;
          }
          // 拖放按钮接收事件
          if (mShowDashBorder && mDragDrawRectF.contains(event.getX(), event.getY())) {
            mode = SINGLE_ZOOM;
            showDashBorder(true);

            mPreDistance =
                Utils.calcDistance(mCenterPoint[0], mCenterPoint[1], event.getX(), event.getY());
            mPreRotation =
                Utils.calcRotation(mCenterPoint[0], mCenterPoint[1], event.getX(), event.getY());
            break;
          }
          /** 判断虚线框是否接收事件; 因旋转后无法直接判断事件是否在rect内, 可将坐标点反向旋转后再与未进行旋转的rect进行比较判断 */
          mDashDrawRectF.set(mDashRectF);
          mViewNoRotateMatrix.mapRect(mDashDrawRectF);
          Matrix inverseMatrix = new Matrix();
          // 获取反向旋转矩阵
          inverseMatrix.postRotate(360 - mCurRotation, mCenterPoint[0], mCenterPoint[1]);
          // 将当前坐标反向旋转,再进行判断
          float[] eventPoint = {event.getX(), event.getY()};
          inverseMatrix.mapPoints(eventPoint);
          if (mDashDrawRectF.contains(eventPoint[0], eventPoint[1])) {
            mode = DRAG;

            mInitTouchX = event.getX();
            mInitTouchY = event.getY();

            mLastTouchX = event.getX();
            mLastTouchY = event.getY();
          } else {
            handled = false;
          }

          showDashBorder(handled);
          if (handled && mListener != null) {
            mListener.onFocus();
            mAlwaysInTapRegion = true;
          }
          break;
        }
      case MotionEvent.ACTION_MOVE:
        {
          if (mAlwaysInTapRegion) {
            float deltaX = event.getX() - mInitTouchX;
            float deltaY = event.getY() - mInitTouchY;
            // 判断是否在点击区域内
            if ((deltaX * deltaX) + (deltaY * deltaY) > mTouchSlopSquare) {
              mAlwaysInTapRegion = false;
            }
          }

          if (mode == SINGLE_ZOOM || mode == DOUBLE_ZOOM) {
            float curDistance, endRotation;
            if (mode == SINGLE_ZOOM) {
              // 单指缩放、旋转
              curDistance =
                  Utils.calcDistance(mCenterPoint[0], mCenterPoint[1], event.getX(), event.getY());
              endRotation =
                  Utils.calcRotation(mCenterPoint[0], mCenterPoint[1], event.getX(), event.getY());
            } else {
              // 双指缩放、旋转
              curDistance = Utils.calcDistance(event);
              endRotation = Utils.calcRotation(event);
            }
            scale(curDistance / mPreDistance);
            mPreDistance = curDistance;

            rotate(endRotation - mPreRotation);
            mPreRotation = endRotation;
          } else if (mode == DRAG) {
            translate(event.getX() - mLastTouchX, event.getY() - mLastTouchY);
            mLastTouchX = event.getX();
            mLastTouchY = event.getY();
          }
          invalidate();
          break;
        }
      case MotionEvent.ACTION_POINTER_DOWN:
        {
          mAlwaysInTapRegion = false;
          if (mode != SINGLE_ZOOM) {
            mode = DOUBLE_ZOOM;
            mPreDistance = Utils.calcDistance(event);
            mPreRotation = Utils.calcRotation(event);
          }
          break;
        }
      case MotionEvent.ACTION_UP:
        {
          mode = NONE;
          mPreRotation = 0.f;

          if (mAlwaysInTapRegion && mPreShowDashBorder && mListener != null) {
            mListener.onClick();
          }
          mAlwaysInTapRegion = false;
          break;
        }
      case MotionEvent.ACTION_POINTER_UP:
        {
          if (mode != SINGLE_ZOOM) {
            mode = NONE;
            mPreRotation = 0.f;
          }
          break;
        }
    }
    return handled;
  }
  public DashFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    setWillNotDraw(false);

    final int margin = Utils.dip2px(context, 5);
    mDelBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_stamp_close);
    mDragBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_stamp_drag);
    setLayoutParams(
        new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

    mDashPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDashPaint.setColor(Color.GRAY);
    mDashPaint.setStyle(Paint.Style.STROKE);
    mDashPaint.setStrokeWidth(3);

    mDashPath = new Path();
    mRefreshHandler = new RefreshHandler(this);

    mDashFloats = new float[] {DASH_ON_WIDTH, DASH_OFF_WIDTH};
    mPathEffects = new PathEffect[mDashMinSize];
    showDashBorder(true);

    mTouchSlopSquare =
        ViewConfiguration.get(context).getScaledTouchSlop()
            * ViewConfiguration.get(context).getScaledTouchSlop();

    getViewTreeObserver()
        .addOnPreDrawListener(
            new ViewTreeObserver.OnPreDrawListener() {
              @Override
              public boolean onPreDraw() {
                if (!isRunPreDrawListener) {
                  return true;
                }
                isRunPreDrawListener = false;

                int childCount = getChildCount();
                if (childCount < 1) {
                  return false;
                }

                Rect rect = new Rect();
                mChildView.getLocalVisibleRect(rect);

                // 计算虚线框绘制位置,注意虚线框与label之间存在margin
                mDashRectF.left = rect.left - margin;
                mDashRectF.top = rect.top - margin;
                mDashRectF.right = rect.right + margin;
                mDashRectF.bottom = rect.bottom + margin;

                // 计算删除按钮初始中心坐标
                mDelPoint[0] = mDashRectF.left;
                mDelPoint[1] = mDashRectF.top;

                // 计算拖放按钮初始中心坐标
                mDragPoint[0] = mDashRectF.right;
                mDragPoint[1] = mDashRectF.bottom;

                if (mViewMatrix.isIdentity()) {
                  mCenterPoint[0] = rect.width() >> 1;
                  mCenterPoint[1] = rect.height() >> 1;
                  int halfWidth = getWidth() >> 1;
                  int halfHeight = getHeight() >> 1;
                  // 移动到中心
                  translate(halfWidth - mCenterPoint[0], halfHeight - mCenterPoint[1]);
                } else {
                  int newCenterX = rect.width() >> 1;
                  int newCenterY = rect.height() >> 1;

                  // 根据新中心调整矩阵
                  mViewMatrix.reset();
                  mViewMatrix.postTranslate(
                      mCenterPoint[0] - newCenterX, mCenterPoint[1] - newCenterY);
                  mViewMatrix.postRotate(mCurRotation, mCenterPoint[0], mCenterPoint[1]);
                  mViewMatrix.postScale(
                      mCurScaleFactor, mCurScaleFactor, mCenterPoint[0], mCenterPoint[1]);

                  mViewNoRotateMatrix.reset();
                  mViewNoRotateMatrix.postTranslate(
                      mCenterPoint[0] - newCenterX, mCenterPoint[1] - newCenterY);
                  mViewNoRotateMatrix.postScale(
                      mCurScaleFactor, mCurScaleFactor, mCenterPoint[0], mCenterPoint[1]);

                  updateBtnDrawRect();
                }
                // 将view转换为bitmap,便于旋转、缩放时提高性能
                mLabelBitmap = ImageUtils.captureScreenByDraw(mChildView);

                mDashPath.reset();
                mDashPath.addRect(mDashRectF, Path.Direction.CCW);
                removeAllViews();
                return true;
              }
            });
  }