/** 画面から消す際の処理を表します。 */
 @Override
 public void setVisibility(int visibility) {
   // 画面表示時
   if (visibility != View.VISIBLE) {
     // 画面から消す時は長押しをキャンセルし、画面端に強制的に移動します。
     cancelLongPress();
     setScale(SCALE_NORMAL);
     if (mIsMoveAccept) {
       moveToEdge(false);
     }
     mAnimationHandler.removeMessages(FloatingAnimationHandler.ANIMATION_IN_TOUCH);
     mLongPressHandler.removeMessages(LongPressHandler.LONG_PRESSED);
   }
   super.setVisibility(visibility);
 }
  /** {@inheritDoc} */
  @Override
  public boolean dispatchTouchEvent(@NonNull MotionEvent event) {
    // Viewが表示されていなければ何もしない
    if (getVisibility() != View.VISIBLE) {
      return true;
    }

    // タッチ不能な場合は何もしない
    if (!mIsDraggable) {
      return true;
    }

    // 現在位置のキャッシュ
    mScreenTouchX = event.getRawX();
    mScreenTouchY = event.getRawY();
    final int action = event.getAction();
    // 押下
    if (action == MotionEvent.ACTION_DOWN) {
      // アニメーションのキャンセル
      cancelAnimation();
      mScreenTouchDownX = mScreenTouchX;
      mScreenTouchDownY = mScreenTouchY;
      mLocalTouchX = event.getX();
      mLocalTouchY = event.getY();
      mIsMoveAccept = false;
      setScale(SCALE_PRESSED);
      // タッチトラッキングアニメーションの開始
      mAnimationHandler.updateTouchPosition(getXByTouch(), getYByTouch());
      mAnimationHandler.removeMessages(FloatingAnimationHandler.ANIMATION_IN_TOUCH);
      mAnimationHandler.sendAnimationMessage(FloatingAnimationHandler.ANIMATION_IN_TOUCH);
      // 長押し判定の開始
      mLongPressHandler.removeMessages(LongPressHandler.LONG_PRESSED);
      mLongPressHandler.sendEmptyMessageDelayed(LongPressHandler.LONG_PRESSED, LONG_PRESS_TIMEOUT);
      // 押下処理の通過判定のための時間保持
      // mIsDraggableやgetVisibility()のフラグが押下後に変更された場合にMOVE等を処理させないようにするため
      mTouchDownTime = event.getDownTime();
    }
    // 移動
    else if (action == MotionEvent.ACTION_MOVE) {
      // 移動判定の場合は長押しの解除
      if (mIsMoveAccept) {
        mIsLongPressed = false;
        mLongPressHandler.removeMessages(LongPressHandler.LONG_PRESSED);
      }
      // 押下処理が行われていない場合は処理しない
      if (mTouchDownTime != event.getDownTime()) {
        return true;
      }
      final float moveThreshold = MOVE_THRESHOLD_DP * mMetrics.density;
      // 移動受付状態でない、かつX,Y軸ともにしきい値よりも小さい場合
      if (!mIsMoveAccept
          && Math.abs(mScreenTouchX - mScreenTouchDownX) < moveThreshold
          && Math.abs(mScreenTouchY - mScreenTouchDownY) < moveThreshold) {
        return true;
      }
      mIsMoveAccept = true;
      mAnimationHandler.updateTouchPosition(getXByTouch(), getYByTouch());
    }
    // 押上、キャンセル
    else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
      // 判定のため長押しの状態を一時的に保持
      final boolean tmpIsLongPressed = mIsLongPressed;
      // 長押しの解除
      mIsLongPressed = false;
      mLongPressHandler.removeMessages(LongPressHandler.LONG_PRESSED);
      // 押下処理が行われていない場合は処理しない
      if (mTouchDownTime != event.getDownTime()) {
        return true;
      }
      // アニメーションの削除
      mAnimationHandler.removeMessages(FloatingAnimationHandler.ANIMATION_IN_TOUCH);
      // 拡大率をもとに戻す
      setScale(SCALE_NORMAL);

      // 動かされていれば画面端に戻す
      if (mIsMoveAccept) {
        moveToEdge(true);
      }
      // 動かされていなければ、クリックイベントを発行
      else {
        if (!tmpIsLongPressed) {
          final int size = getChildCount();
          for (int i = 0; i < size; i++) {
            getChildAt(i).performClick();
          }
        }
      }
    }

    // タッチリスナを通知
    if (mOnTouchListener != null) {
      mOnTouchListener.onTouch(this, event);
    }

    return true;
  }