This commit is contained in:
lunaticbum 2026-03-23 14:53:26 +09:00
parent a8c7641e69
commit 9aee32e42d
3 changed files with 60 additions and 27 deletions

View File

@ -1084,7 +1084,12 @@ class FloatingActionButton : ImageButton {
if (animate) {
playHideAnimation()
}
super.setVisibility(INVISIBLE)
if (this.isSelected) {
super.setVisibility(GONE)
} else {
super.setVisibility(INVISIBLE)
}
}
}

View File

@ -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..<getChildCount()) {
val child = getChildAt(i)
if (child is FloatingActionButton && child.getVisibility() != GONE) {
counter++

View File

@ -65,26 +65,31 @@
android:id="@+id/perplexity"/>
<bums.lunatic.launcher.view.FloatingActionButton
app:fab_label="😂"
android:visibility="gone"
style="@style/CommonFabStyle"
android:id="@+id/zzalbang"/>
<bums.lunatic.launcher.view.FloatingActionButton
app:fab_label="🐦"
android:visibility="gone"
style="@style/CommonFabStyle"
android:id="@+id/btn_x"/>
<bums.lunatic.launcher.view.FloatingActionButton
app:fab_label="🔞"
android:visibility="gone"
style="@style/CommonFabStyle"
android:id="@+id/btn_i"/>
<bums.lunatic.launcher.view.FloatingActionButton
app:fab_label="🧲"
android:visibility="gone"
style="@style/CommonFabStyle"
android:id="@+id/btn_torrent"
/>
<bums.lunatic.launcher.view.FloatingActionButton
app:fab_label="📦"
android:visibility="gone"
style="@style/CommonFabStyle"
android:id="@+id/btn_completed_files"
/>