[go: nahoru, domu]

blob: 858842f5ee53735a87f6ee26b7e8af6fb5b25d6c [file] [log] [blame]
/*
* 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.compose.foundation.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.compose.foundation.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
}
}