forked from shihaam/thijooree
auto rotate wheel when tapping icon
This commit is contained in:
@@ -23,6 +23,8 @@ import kotlin.math.*
|
|||||||
|
|
||||||
class CircularNavFragment : Fragment() {
|
class CircularNavFragment : Fragment() {
|
||||||
|
|
||||||
|
private var wheelView: CircularWheelView? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@@ -47,9 +49,10 @@ class CircularNavFragment : Fragment() {
|
|||||||
android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f
|
android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0, 1f
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val wheelView = CircularWheelView(ctx).apply {
|
val prefs = ctx.getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||||
|
wheelView = CircularWheelView(ctx).apply {
|
||||||
layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
||||||
val prefs = ctx.getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
wheelAngle = prefs.getFloat("circular_wheel_angle", 0f)
|
||||||
val savedSlots = NavCustomization.getCircularSlots(prefs).map { id ->
|
val savedSlots = NavCustomization.getCircularSlots(prefs).map { id ->
|
||||||
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == id }!!
|
val def = NavCustomization.ALL_SWAPPABLE.find { it.id == id }!!
|
||||||
CircularWheelView.WheelItem(def.id, def.iconRes, ctx.getString(def.titleRes))
|
CircularWheelView.WheelItem(def.id, def.iconRes, ctx.getString(def.titleRes))
|
||||||
@@ -112,6 +115,10 @@ class CircularNavFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
wheelView?.let { wv ->
|
||||||
|
requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||||
|
.edit().putFloat("circular_wheel_angle", wv.wheelAngle).apply()
|
||||||
|
}
|
||||||
val toolbar = requireActivity().findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
val toolbar = requireActivity().findViewById<com.google.android.material.appbar.MaterialToolbar>(R.id.toolbar)
|
||||||
toolbar.findViewWithTag<android.view.View>("wheel_title")?.let { toolbar.removeView(it) }
|
toolbar.findViewWithTag<android.view.View>("wheel_title")?.let { toolbar.removeView(it) }
|
||||||
requireActivity().invalidateOptionsMenu()
|
requireActivity().invalidateOptionsMenu()
|
||||||
@@ -181,7 +188,7 @@ class CircularWheelView @JvmOverloads constructor(
|
|||||||
|
|
||||||
// ---- touch & fling ----------------------------------------------------
|
// ---- touch & fling ----------------------------------------------------
|
||||||
|
|
||||||
private var wheelAngle = 0f
|
var wheelAngle = 0f
|
||||||
private var isDragging = false
|
private var isDragging = false
|
||||||
private var snapAnimator: ValueAnimator? = null
|
private var snapAnimator: ValueAnimator? = null
|
||||||
|
|
||||||
@@ -358,7 +365,7 @@ class CircularWheelView @JvmOverloads constructor(
|
|||||||
dist <= innerRadius -> onCenterClick?.invoke()
|
dist <= innerRadius -> onCenterClick?.invoke()
|
||||||
dist <= outerRadius -> {
|
dist <= outerRadius -> {
|
||||||
val idx = segmentAt(event.x, event.y)
|
val idx = segmentAt(event.x, event.y)
|
||||||
if (idx in items.indices) onItemClick?.invoke(items[idx].navId)
|
if (idx in items.indices) animateToSixOClock(idx) { onItemClick?.invoke(items[idx].navId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -423,6 +430,30 @@ class CircularWheelView @JvmOverloads constructor(
|
|||||||
return (a / (360f / items.size)).toInt() % items.size
|
return (a / (360f / items.size)).toInt() % items.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun animateToSixOClock(index: Int, onDone: () -> Unit) {
|
||||||
|
val segDeg = 360f / items.size.coerceAtLeast(1)
|
||||||
|
val midDeg = index * segDeg + segDeg / 2f
|
||||||
|
// delta needed so this segment's midpoint lands at 90° (6 o'clock in math coords)
|
||||||
|
var delta = (90f - midDeg) - wheelAngle
|
||||||
|
// normalise to shortest path [-180, 180]
|
||||||
|
delta = ((delta % 360f) + 360f) % 360f
|
||||||
|
if (delta > 180f) delta -= 360f
|
||||||
|
val endAngle = wheelAngle + delta
|
||||||
|
|
||||||
|
snapAnimator?.cancel()
|
||||||
|
snapAnimator = ValueAnimator.ofFloat(wheelAngle, endAngle).apply {
|
||||||
|
duration = 350
|
||||||
|
interpolator = DecelerateInterpolator()
|
||||||
|
addUpdateListener { wheelAngle = it.animatedValue as Float; invalidate() }
|
||||||
|
addListener(object : AnimatorListenerAdapter() {
|
||||||
|
private var cancelled = false
|
||||||
|
override fun onAnimationCancel(a: Animator) { cancelled = true }
|
||||||
|
override fun onAnimationEnd(a: Animator) { if (!cancelled) onDone() }
|
||||||
|
})
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun snapToNearest() {
|
private fun snapToNearest() {
|
||||||
val segDeg = 360f / items.size.coerceAtLeast(1)
|
val segDeg = 360f / items.size.coerceAtLeast(1)
|
||||||
val target = (wheelAngle / segDeg).roundToInt() * segDeg
|
val target = (wheelAngle / segDeg).roundToInt() * segDeg
|
||||||
|
|||||||
Reference in New Issue
Block a user