Skip to content

Instantly share code, notes, and snippets.

@MinceMan
Created September 20, 2017 22:27
Show Gist options
  • Save MinceMan/37d4df379cb5322f74333639e4d58597 to your computer and use it in GitHub Desktop.
Save MinceMan/37d4df379cb5322f74333639e4d58597 to your computer and use it in GitHub Desktop.
package com.bfreq.dice.widget
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import com.bfreq.dice.R
import com.bfreq.dice.util.forEachChild
import com.bfreq.dice.util.forEachChildIndexed
/**
* All children of this class will be laid out in a circle.
* This assumes all children are square.
* There is no visibility support as of now.
*/
class CircularLayout : ViewGroup {
private val outerCircularPadding = resources.getDimensionPixelSize(R.dimen.circular_padding)
private val startingRadianOffset = -(2 * Math.PI / 4) // rotates to noon.
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
/**
* This makes sure that no view is at the 12 o'clock position.
* Changing this value will request a layout.
*/
var isAdjustingOffNoon = false
set(value) {
field = value
requestLayout()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
forEachChild { measureChild(it, widthMeasureSpec, heightMeasureSpec) }
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
val radianPerChild = 2 * Math.PI / childCount
val adjustOffNoon: Double = if (isAdjustingOffNoon) radianPerChild / 2 else 0.0
val cx = width / 2
val cy = height / 2
forEachChildIndexed {
index, child ->
val radian = radianPerChild * index + startingRadianOffset + adjustOffNoon
layoutChild(radian, cx, cy, child)
}
}
fun layoutChild(radian: Double, parentCenterX: Int, parentCenterY: Int, child: View) {
val radius = width / 2 - (child.measuredWidth / 2 + outerCircularPadding)
val childCenterX = parentCenterX + radius * Math.cos(radian)
val childCenterY = parentCenterY + radius * Math.sin(radian)
child.layout(
(childCenterX - child.measuredWidth / 2).toInt(),
(childCenterY - child.measuredHeight / 2).toInt(),
(childCenterX + child.measuredWidth / 2).toInt(),
(childCenterY + child.measuredHeight / 2).toInt()
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment