Created
September 20, 2017 22:27
-
-
Save MinceMan/37d4df379cb5322f74333639e4d58597 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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