diff options
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.kt | 107 |
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) + +} |