aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt')
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt107
1 files changed, 107 insertions, 0 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
new file mode 100644
index 0000000..edc1536
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
@@ -0,0 +1,107 @@
+package ca.allanwang.kau.ui.views
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.View
+import ca.allanwang.kau.R
+import ca.allanwang.kau.utils.parentViewGroup
+
+/**
+ * Created by Allan Wang on 2017-07-14.
+ *
+ * Handles relative sizes for any view
+ */
+interface MeasureSpecContract {
+
+ /**
+ * Width will be calculated as a percentage of the parent
+ * This takes precedence over relativeWidth
+ */
+ var relativeWidthToParent: Float
+ /**
+ * Height will be calculated as a percentage of the parent
+ * This takes precedence over relativeHeight
+ */
+ var relativeHeightToParent: Float
+ /**
+ * Width will be calculated based on the measured height
+ */
+ var relativeWidth: Float
+ /**
+ * Height will be calculated based on the measure width
+ */
+ var relativeHeight: Float
+ /**
+ * Width will be once again calculated from the current measured height
+ * This is the last step
+ */
+ var postRelativeWidth: Float
+ /**
+ * Height will be once again calculated from the current measured width
+ * This is the last step
+ */
+ var postRelativeHeight: Float
+
+ /**
+ * Retrieves relative values from the [AttributeSet]
+ * Call this on init
+ */
+ fun initAttrs(context: Context, attrs: AttributeSet?)
+
+ /**
+ * Calculates the final measure specs
+ * Call this from [View.onMeasure] and send the Pair result as the specs
+ * The pair is of the format (width, height)
+ */
+ fun onMeasure(view: View, widthMeasureSpec: Int, heightMeasureSpec: Int): Pair<Int, Int>
+}
+
+class MeasureSpecDelegate : MeasureSpecContract {
+
+ override var relativeWidth = -1f
+ override var relativeHeight = -1f
+ override var relativeWidthToParent = -1f
+ override var relativeHeightToParent = -1f
+ override var postRelativeWidth: Float = -1f
+ override var postRelativeHeight: Float = -1f
+ private val parentFrame = Rect()
+
+ override fun initAttrs(context: Context, attrs: AttributeSet?) {
+ if (attrs == null) return
+ val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MeasureSpecDelegate)
+ relativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidth, relativeWidth)
+ relativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeight, relativeHeight)
+ relativeWidthToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidthToParent, relativeWidthToParent)
+ relativeHeightToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeightToParent, relativeHeightToParent)
+ postRelativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeWidth, postRelativeWidth)
+ postRelativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeHeight, postRelativeHeight)
+ styledAttrs.recycle()
+ }
+
+ override fun onMeasure(view: View, widthMeasureSpec: Int, heightMeasureSpec: Int): Pair<Int, Int> {
+ view.parentViewGroup.getWindowVisibleDisplayFrame(parentFrame)
+ var width = View.MeasureSpec.getSize(widthMeasureSpec).toFloat()
+ var height = View.MeasureSpec.getSize(heightMeasureSpec).toFloat()
+ //first cycle - relative to parent
+ if (relativeHeightToParent > 0)
+ height = relativeHeightToParent * parentFrame.height()
+ if (relativeWidthToParent > 0)
+ width = relativeWidthToParent * parentFrame.width()
+ //second cycle - relative to each other
+ if (relativeHeight > 0)
+ height = relativeHeight * width
+ else if (relativeWidth > 0)
+ width = relativeWidth * height
+ //third cycle - relative to each other
+ if (postRelativeHeight > 0)
+ height = postRelativeHeight * width
+ else if (postRelativeWidth > 0)
+ width = postRelativeWidth * height
+ return Pair(width.measureSpec, height.measureSpec)
+ }
+
+ private val Float.measureSpec: Int
+ get() = View.MeasureSpec.makeMeasureSpec(this.toInt(), View.MeasureSpec.EXACTLY)
+
+}