[go: nahoru, domu]

ui-layout to MPP

Test: ./gradlew buildOnServer
Change-Id: Iad0c0a2dd0004b38518c6080e721e4e39dab0da2
Relnote: N/A
diff --git a/ui/ui-layout/src/commonMain/kotlin/androidx/ui/layout/LayoutAspectRatio.kt b/ui/ui-layout/src/commonMain/kotlin/androidx/ui/layout/LayoutAspectRatio.kt
new file mode 100644
index 0000000..4c891a2
--- /dev/null
+++ b/ui/ui-layout/src/commonMain/kotlin/androidx/ui/layout/LayoutAspectRatio.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.layout
+
+import androidx.compose.Stable
+import androidx.ui.core.Constraints
+import androidx.ui.core.IntrinsicMeasurable
+import androidx.ui.core.IntrinsicMeasureScope
+import androidx.ui.core.LayoutDirection
+import androidx.ui.core.LayoutModifier
+import androidx.ui.core.Measurable
+import androidx.ui.core.MeasureScope
+import androidx.ui.core.Modifier
+import androidx.ui.core.satisfiedBy
+import androidx.ui.unit.IntSize
+import androidx.ui.util.annotation.FloatRange
+import kotlin.math.roundToInt
+
+/**
+ * Attempts to size the content to match a specified aspect ratio by trying to match one of the
+ * incoming constraints in the following order:
+ * [Constraints.maxWidth], [Constraints.maxHeight], [Constraints.minWidth], [Constraints.minHeight].
+ * The size in the other dimension is determined by the aspect ratio.
+ *
+ * Example usage:
+ * @sample androidx.ui.layout.samples.SimpleAspectRatio
+ *
+ * @param ratio the desired width/height positive ratio
+ */
+@Stable
+fun Modifier.aspectRatio(
+    @FloatRange(from = 0.0, to = 3.4e38 /* POSITIVE_INFINITY */, fromInclusive = false)
+    ratio: Float
+) = this + AspectRatioModifier(ratio)
+
+private data class AspectRatioModifier(val aspectRatio: Float) : LayoutModifier {
+    init {
+        require(aspectRatio > 0) { "aspectRatio $aspectRatio must be > 0" }
+    }
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints,
+        layoutDirection: LayoutDirection
+    ): MeasureScope.MeasureResult {
+        val size = constraints.findSizeWith(aspectRatio)
+        val wrappedConstraints = if (size != null) {
+            Constraints.fixed(size.width, size.height)
+        } else {
+            constraints
+        }
+        val placeable = measurable.measure(wrappedConstraints)
+        return layout(placeable.width, placeable.height) {
+            placeable.place(0, 0)
+        }
+    }
+
+    override fun IntrinsicMeasureScope.minIntrinsicWidth(
+        measurable: IntrinsicMeasurable,
+        height: Int,
+        layoutDirection: LayoutDirection
+    ) = if (height != Constraints.Infinity) {
+        (height * aspectRatio).roundToInt()
+    } else {
+        measurable.minIntrinsicWidth(height)
+    }
+
+    override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+        measurable: IntrinsicMeasurable,
+        height: Int,
+        layoutDirection: LayoutDirection
+    ) = if (height != Constraints.Infinity) {
+        (height * aspectRatio).roundToInt()
+    } else {
+        measurable.maxIntrinsicWidth(height)
+    }
+
+    override fun IntrinsicMeasureScope.minIntrinsicHeight(
+        measurable: IntrinsicMeasurable,
+        width: Int,
+        layoutDirection: LayoutDirection
+    ) = if (width != Constraints.Infinity) {
+        (width / aspectRatio).roundToInt()
+    } else {
+        measurable.minIntrinsicHeight(width)
+    }
+
+    override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+        measurable: IntrinsicMeasurable,
+        width: Int,
+        layoutDirection: LayoutDirection
+    ) = if (width != Constraints.Infinity) {
+        (width / aspectRatio).roundToInt()
+    } else {
+        measurable.maxIntrinsicHeight(width)
+    }
+
+    private fun Constraints.findSizeWith(aspectRatio: Float): IntSize? {
+        val maxWidth = this.maxWidth
+        if (maxWidth != Constraints.Infinity) {
+            val height = (maxWidth / aspectRatio).roundToInt()
+            if (height > 0) {
+                val size = IntSize(maxWidth, height)
+                if (satisfiedBy(size)) {
+                    return size
+                }
+            }
+        }
+        val maxHeight = this.maxHeight
+        if (maxHeight != Constraints.Infinity) {
+            val width = (maxHeight * aspectRatio).roundToInt()
+            if (width > 0) {
+                val size = IntSize(width, maxHeight)
+                if (satisfiedBy(size)) {
+                    return size
+                }
+            }
+        }
+        val minWidth = this.minWidth
+        val height = (minWidth / aspectRatio).roundToInt()
+        if (height > 0) {
+            val size = IntSize(minWidth, height)
+            if (satisfiedBy(size)) {
+                return size
+            }
+        }
+        val minHeight = this.minHeight
+        val width = (minHeight * aspectRatio).roundToInt()
+        if (width > 0) {
+            val size = IntSize(width, minHeight)
+            if (satisfiedBy(size)) {
+                return size
+            }
+        }
+        return null
+    }
+}