From 9aee32e42d6351f2e5cc3121a2c7c768448e1ca6 Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Mon, 23 Mar 2026 14:53:26 +0900 Subject: [PATCH] ... --- .../launcher/view/FloatingActionButton.kt | 7 +- .../launcher/view/FloatingActionMenu.kt | 75 ++++++++++++------- app/src/main/res/layout/rss_activity.xml | 5 ++ 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionButton.kt b/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionButton.kt index 1afe0b29..aec18e97 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionButton.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionButton.kt @@ -1084,7 +1084,12 @@ class FloatingActionButton : ImageButton { if (animate) { playHideAnimation() } - super.setVisibility(INVISIBLE) + + if (this.isSelected) { + super.setVisibility(GONE) + } else { + super.setVisibility(INVISIBLE) + } } } diff --git a/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionMenu.kt b/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionMenu.kt index 7468d0db..6474baf2 100644 --- a/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionMenu.kt +++ b/app/src/main/kotlin/bums/lunatic/launcher/view/FloatingActionMenu.kt @@ -11,10 +11,12 @@ import android.graphics.Color import android.graphics.Typeface import android.graphics.drawable.Drawable import android.os.Handler +import android.os.Looper import android.text.TextUtils import android.util.AttributeSet import android.util.TypedValue import android.view.ContextThemeWrapper +import android.view.HapticFeedbackConstants import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -570,12 +572,24 @@ class FloatingActionMenu @JvmOverloads constructor( } }) + + mMenuButton!!.setOnTouchListener(object : OnTouchListener { var dX: Float = 0f var dY: Float = 0f var startX: Float = 0f var startY: Float = 0f + // ๐Ÿ’ก ๋กฑํด๋ฆญ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ๋ณ€์ˆ˜ ์ถ”๊ฐ€ + private val longClickHandler = Handler(Looper.getMainLooper()) + private var isLongClickPerformed = false + private val longClickRunnable = Runnable { + isLongClickPerformed = true + // ์—ฌ๊ธฐ์— ๋กฑํด๋ฆญ ์‹œ ์‹คํ–‰ํ•  ๋™์ž‘์„ ๋„ฃ์œผ์„ธ์š”. + // ์˜ˆ: Vibrator ์‹คํ–‰ ๋˜๋Š” ํŠน์ • ํ•จ์ˆ˜ ํ˜ธ์ถœ + performLongClickAction() + } + override fun onTouch(v: View, event: MotionEvent): Boolean { val oldX = v.x val oldY = v.y @@ -586,48 +600,52 @@ class FloatingActionMenu @JvmOverloads constructor( dY = v.y - event.rawY startX = event.rawX startY = event.rawY + + // ๐Ÿ’ก 1. 500ms ๋’ค์— ๋กฑํด๋ฆญ์œผ๋กœ ๊ฐ„์ฃผํ•˜๋„๋ก ์˜ˆ์•ฝ + isLongClickPerformed = false + longClickHandler.postDelayed(longClickRunnable, 500) } MotionEvent.ACTION_MOVE -> { - if (!isDragMenuDisabled) { - // 1. ๋“œ๋ž˜๊ทธํ•˜๋ ค๋Š” ๋ชฉํ‘œ ์ขŒํ‘œ ๊ณ„์‚ฐ - var newX = event.rawX + dX - var newY = event.rawY + dY + // ๐Ÿ’ก 2. ์‚ฌ์šฉ์ž๊ฐ€ ์ผ์ • ๊ฑฐ๋ฆฌ ์ด์ƒ ์›€์ง์ด๋ฉด ๋กฑํด๋ฆญ ์˜ˆ์•ฝ์„ ์ทจ์†Œ (๋“œ๋ž˜๊ทธ๋กœ ํŒ๋‹จ) + if (abs(startX - event.rawX) > 10 || abs(startY - event.rawY) > 10) { + longClickHandler.removeCallbacks(longClickRunnable) + } - // 2. ํ™”๋ฉด ์ „์ฒด ๋„ˆ๋น„์™€ ๋†’์ด ๊ฐ€์ ธ์˜ค๊ธฐ (ํ˜„์žฌ FloatingActionMenu๊ฐ€ match_parent์ด๋ฏ€๋กœ ์ž์ฒด ํฌ๊ธฐ ์‚ฌ์šฉ) - val menuWidth = this@FloatingActionMenu.width - val menuHeight = this@FloatingActionMenu.height + if (!isDragMenuDisabled && !isLongClickPerformed) { + // ๋“œ๋ž˜๊ทธ ๋กœ์ง (๊ธฐ์กด๊ณผ ๋™์ผ) + var newX = (event.rawX + dX).coerceIn(paddingLeft.toFloat(), (this@FloatingActionMenu.width - v.width - paddingRight).toFloat()) + var newY = (event.rawY + dY).coerceIn(paddingTop.toFloat(), (this@FloatingActionMenu.height - v.height - paddingBottom).toFloat()) - // 3. ํ™”๋ฉด์„ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๋„๋ก ์ขŒํ‘œ ๊ฐ€๋‘๊ธฐ (ํŒจ๋”ฉ ํฌํ•จ) - val minX = paddingLeft.toFloat() - val maxX = (menuWidth - v.width - paddingRight).toFloat() - - val minY = paddingTop.toFloat() - val maxY = (menuHeight - v.height - paddingBottom).toFloat() - - // coerceIn ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์†Œ~์ตœ๋Œ€ ๊ฐ’ ์‚ฌ์ด๋กœ ๊ฐ•์ œ ๋ณด์ • - newX = newX.coerceIn(minX, maxX) - newY = newY.coerceIn(minY, maxY) - - // 4. ๋ณด์ •๋œ ์ขŒํ‘œ๋กœ ๋ทฐ ์ด๋™ v.x = newX v.y = newY - - // 5. ํ•˜์œ„ ๋ฉ”๋‰ด๋“ค๋„ ๋ฐ”๋€ ๋ฉ”์ธ ๋ฒ„ํŠผ ์œ„์น˜์— ๋งž์ถฐ ๋‹ค์‹œ ๊ทธ๋ฆฌ๊ธฐ moveElements(v, newX, newY, oldX, oldY) } } MotionEvent.ACTION_UP -> { - // ๋“œ๋ž˜๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋‹จ์ˆœ ํด๋ฆญ(์˜ค์ฐจ 10ํ”ฝ์…€ ์ด๋‚ด)์ด์—ˆ๋‹ค๋ฉด ๋ฉ”๋‰ด ํ† ๊ธ€ + // ๐Ÿ’ก 3. ์†์„ ๋–ผ๋ฉด ์˜ˆ์•ฝ๋œ ๋กฑํด๋ฆญ ์ทจ์†Œ + longClickHandler.removeCallbacks(longClickRunnable) + + // ๋กฑํด๋ฆญ์ด ์ด๋ฏธ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋ฌด์‹œ + if (isLongClickPerformed) return true + if (abs(startX - event.rawX) < 10 && abs(startY - event.rawY) < 10) { toggle(mIsAnimated) } } - else -> return false + MotionEvent.ACTION_CANCEL -> { + // ๐Ÿ’ก 4. ์ทจ์†Œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ์—๋„ ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ + longClickHandler.removeCallbacks(longClickRunnable) + } } return true } + + private fun performLongClickAction() { + mMenuButton!!.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + toggle(animate = mIsAnimated, true) + } }) } } @@ -795,15 +813,15 @@ class FloatingActionMenu @JvmOverloads constructor( return super.onTouchEvent(event) } - fun toggle(animate: Boolean) { + fun toggle(animate: Boolean, allShow: Boolean = false) { if (this.isOpened) { close(animate) } else { - open(animate) + open(animate, allShow) } } - fun open(animate: Boolean) { + fun open(animate: Boolean, allShow : Boolean = false) { if (!this.isOpened) { if (this.isBackgroundEnabled) { mShowBackgroundAnimator!!.start() @@ -823,6 +841,10 @@ class FloatingActionMenu @JvmOverloads constructor( mIsMenuOpening = true for (i in getChildCount() - 1 downTo 0) { val child = getChildAt(i) + if (allShow && !child.equals(mMenuButton) && child.getVisibility() == GONE) { + child.isSelected = true + child.visibility = View.INVISIBLE + } if (child is FloatingActionButton && child.getVisibility() != GONE) { counter++ @@ -877,6 +899,7 @@ class FloatingActionMenu @JvmOverloads constructor( mIsMenuOpening = false for (i in 0..