/** 画面サイズから自位置を決定します。 */ private void updateViewLayout() { cancelAnimation(); // 前の画面座標を保存 final int oldScreenHeight = mMetrics.heightPixels; final int oldScreenWidth = mMetrics.widthPixels; final int oldPositionLimitWidth = mPositionLimitRect.width(); final int oldPositionLimitHeight = mPositionLimitRect.height(); // 新しい座標情報に切替 mWindowManager.getDefaultDisplay().getMetrics(mMetrics); final int width = getMeasuredWidth(); final int height = getMeasuredHeight(); final int newScreenWidth = mMetrics.widthPixels; final int newScreenHeight = mMetrics.heightPixels; // 移動範囲の設定 mMoveLimitRect.set(-width, -height * 2, newScreenWidth + width, newScreenHeight + height); mPositionLimitRect.set( -mOverMargin, 0, newScreenWidth - width + mOverMargin, newScreenHeight - mStatusBarHeight - height); // 縦横切替の場合 if (oldScreenWidth != newScreenWidth || oldScreenHeight != newScreenHeight) { // 画面端に移動する場合は現在の位置から左右端を設定 if (mMoveDirection == FloatingViewManager.MOVE_DIRECTION_DEFAULT) { // 右半分にある場合 if (mParams.x > (newScreenWidth - width) / 2) { mParams.x = mPositionLimitRect.right; } // 左半分にある場合 else { mParams.x = mPositionLimitRect.left; } } // 左端に移動 else if (mMoveDirection == FloatingViewManager.MOVE_DIRECTION_LEFT) { mParams.x = mPositionLimitRect.left; } // 右端に移動 else if (mMoveDirection == FloatingViewManager.MOVE_DIRECTION_RIGHT) { mParams.x = mPositionLimitRect.right; } // 画面端に移動しない場合は画面座標の比率から計算 else { final int newX = (int) (mParams.x * mPositionLimitRect.width() / (float) oldPositionLimitWidth + 0.5f); mParams.x = Math.min(Math.max(mPositionLimitRect.left, newX), mPositionLimitRect.right); } // スクリーン位置の比率からY座標を設定(四捨五入) final int newY = (int) (mParams.y * mPositionLimitRect.height() / (float) oldPositionLimitHeight + 0.5f); mParams.y = Math.min(Math.max(mPositionLimitRect.top, newY), mPositionLimitRect.bottom); mWindowManager.updateViewLayout(this, mParams); } }
/** {@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; }