[go: nahoru, domu]

blob: 9cc84d22b2b37cf0c0c59f20d25a45476923892b [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.ui.core.samples
import androidx.annotation.Sampled
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.Constraints
import androidx.ui.core.ExperimentalLayoutNodeApi
import androidx.ui.core.Layout
import androidx.ui.core.Modifier
import androidx.ui.core.id
import androidx.ui.core.layoutId
import androidx.compose.foundation.Box
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Stack
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.offset
import androidx.ui.core.layout
import androidx.ui.core.measureBlocksOf
@Sampled
@Composable
fun LayoutWithProvidedIntrinsicsUsage(children: @Composable () -> Unit) {
// We build a layout that will occupy twice as much space as its children,
// and will position them to be bottom right aligned.
Layout(
children,
minIntrinsicWidthMeasureBlock = { measurables, h ->
// The min intrinsic width of this layout will be twice the largest min intrinsic
// width of a child. Note that we call minIntrinsicWidth with h / 2 for children,
// since we should be double the size of the children.
(measurables.map { it.minIntrinsicWidth(h / 2) }.maxByOrNull { it } ?: 0) * 2
},
minIntrinsicHeightMeasureBlock = { measurables, w ->
(measurables.map { it.minIntrinsicHeight(w / 2) }.maxByOrNull { it } ?: 0) * 2
},
maxIntrinsicWidthMeasureBlock = { measurables, h ->
(measurables.map { it.maxIntrinsicHeight(h / 2) }.maxByOrNull { it } ?: 0) * 2
},
maxIntrinsicHeightMeasureBlock = { measurables, w ->
(measurables.map { it.maxIntrinsicHeight(w / 2) }.maxByOrNull { it } ?: 0) * 2
}
) { measurables, constraints ->
// measurables contains one element corresponding to each of our layout children.
// constraints are the constraints that our parent is currently measuring us with.
val childConstraints = Constraints(
minWidth = constraints.minWidth / 2,
minHeight = constraints.minHeight / 2,
maxWidth = constraints.maxWidth / 2,
maxHeight = constraints.maxHeight / 2
)
// We measure the children with half our constraints, to ensure we can be double
// the size of the children.
val placeables = measurables.map { it.measure(childConstraints) }
val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
// We call layout to set the size of the current layout and to provide the positioning
// of the children. The children are placed relative to the current layout place.
layout(layoutWidth, layoutHeight) {
placeables.forEach { it.place(layoutWidth - it.width, layoutHeight - it.height) }
}
}
}
@Sampled
@Composable
@OptIn(ExperimentalLayoutNodeApi::class)
fun LayoutWithMeasureBlocksWithIntrinsicUsage(children: @Composable () -> Unit) {
val measureBlocks = measureBlocksOf(
minIntrinsicWidthMeasureBlock = { measurables, h ->
// The min intrinsic width of this layout will be twice the largest min intrinsic
// width of a child. Note that we call minIntrinsicWidth with h / 2 for children,
// since we should be double the size of the children.
(measurables.map { it.minIntrinsicWidth(h / 2) }.maxByOrNull { it } ?: 0) * 2
},
minIntrinsicHeightMeasureBlock = { measurables, w ->
(measurables.map { it.minIntrinsicHeight(w / 2) }.maxByOrNull { it } ?: 0) * 2
},
maxIntrinsicWidthMeasureBlock = { measurables, h ->
(measurables.map { it.maxIntrinsicHeight(h / 2) }.maxByOrNull { it } ?: 0) * 2
},
maxIntrinsicHeightMeasureBlock = { measurables, w ->
(measurables.map { it.maxIntrinsicHeight(w / 2) }.maxByOrNull { it } ?: 0) * 2
}
) { measurables, constraints ->
// measurables contains one element corresponding to each of our layout children.
// constraints are the constraints that our parent is currently measuring us with.
val childConstraints = Constraints(
minWidth = constraints.minWidth / 2,
minHeight = constraints.minHeight / 2,
maxWidth = constraints.maxWidth / 2,
maxHeight = constraints.maxHeight / 2
)
// We measure the children with half our constraints, to ensure we can be double
// the size of the children.
val placeables = measurables.map { it.measure(childConstraints) }
val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
// We call layout to set the size of the current layout and to provide the positioning
// of the children. The children are placed relative to the current layout place.
layout(layoutWidth, layoutHeight) {
placeables.forEach { it.place(layoutWidth - it.width, layoutHeight - it.height) }
}
}
Layout(children = children, measureBlocks = measureBlocks)
}
@Sampled
@Composable
fun LayoutUsage(children: @Composable () -> Unit) {
// We build a layout that will occupy twice as much space as its children,
// and will position them to be bottom right aligned.
Layout(children) { measurables, constraints ->
// measurables contains one element corresponding to each of our layout children.
// constraints are the constraints that our parent is currently measuring us with.
val childConstraints = Constraints(
minWidth = constraints.minWidth / 2,
minHeight = constraints.minHeight / 2,
maxWidth = constraints.maxWidth / 2,
maxHeight = constraints.maxHeight / 2
)
// We measure the children with half our constraints, to ensure we can be double
// the size of the children.
val placeables = measurables.map { it.measure(childConstraints) }
val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
// We call layout to set the size of the current layout and to provide the positioning
// of the children. The children are placed relative to the current layout place.
layout(layoutWidth, layoutHeight) {
placeables.forEach { it.place(layoutWidth - it.width, layoutHeight - it.height) }
}
}
}
@Sampled
@Composable
fun LayoutTagChildrenUsage(header: @Composable () -> Unit, footer: @Composable () -> Unit) {
Layout({
// Here the Containers are only needed to apply the modifiers. You could use the
// modifier on header and footer directly if they are composables accepting modifiers.
Box(Modifier.layoutId("header"), children = header)
Box(Modifier.layoutId("footer"), children = footer)
}) { measurables, constraints ->
val placeables = measurables.map { measurable ->
when (measurable.id) {
// You should use appropriate constraints. Here we measure fake constraints.
"header" -> measurable.measure(Constraints.fixed(100, 100))
"footer" -> measurable.measure(constraints)
else -> error("Unexpected tag")
}
}
// Size should be derived from children measured sizes on placeables,
// but this is simplified for the purposes of the example.
layout(100, 100) {
placeables.forEach { it.place(0, 0) }
}
}
}
@Sampled
@Composable
fun ConvenienceLayoutModifierSample() {
Stack(
modifier = Modifier
.background(Color.Gray)
.layout { measurable, constraints ->
// an example modifier that adds 50 pixels of vertical padding
val padding = 50
val placeable = measurable.measure(constraints.offset(vertical = -padding))
this.layout(placeable.width, placeable.height + padding) {
placeable.place(0, padding)
}
}
) {
Stack(Modifier.fillMaxSize().background(Color.DarkGray)) {}
}
}