Android Compose:Alignment(一)
Alignment是Compse中唯一控制布局位置的接口,源码:
@Stable
fun interface Alignment {
/**
* 在布局容器中使用,通过尺寸和布局规则计算出偏移量
* 详情详细信息见自定义布局
*/
fun align(size: IntSize, space: IntSize, layoutDirection: LayoutDirection): IntOffset
/**
* 横向布局接口:在布局容器内可用宽度区域内,计算子控件的位置
* 横向布局时,开始位置分类左开始或右开始
* 所在此接口中包含LayoutDirection字段,而后面的Vertical接口中没有
*/
@Stable
fun interface Horizontal {
/**
* 计算布局容器可用宽度内的位置接口
*/
fun align(size: Int, space: Int, layoutDirection: LayoutDirection): Int
}
/**
* 纵向布局接口:在使用和Horizontal一样,由于纵向不像横向布局有两个起始位置
* 所以align方法中少了一个LayoutDirection参数
*/
@Stable
fun interface Vertical {
/**
* 计算布局容器可用宽度内的位置接口
*/
fun align(size: Int, space: Int): Int
}
/**
* 在布局方向确定时,常用的对齐集合
*/
companion object {
// 以下是我们常用的变量参数,常与Modifier.align()使用
@Stable
val TopStart: Alignment = BiasAlignment(-1f, -1f)
@Stable
val TopCenter: Alignment = BiasAlignment(0f, -1f)
@Stable
val TopEnd: Alignment = BiasAlignment(1f, -1f)
@Stable
val CenterStart: Alignment = BiasAlignment(-1f, 0f)
@Stable
val Center: Alignment = BiasAlignment(0f, 0f)
@Stable
val CenterEnd: Alignment = BiasAlignment(1f, 0f)
@Stable
val BottomStart: Alignment = BiasAlignment(-1f, 1f)
@Stable
val BottomCenter: Alignment = BiasAlignment(0f, 1f)
@Stable
val BottomEnd: Alignment = BiasAlignment(1f, 1f)
// 纵向布局参数,不常用,一般用在布局参数中或在布局中使用
@Stable
val Top: Vertical = BiasAlignment.Vertical(-1f)
@Stable
val CenterVertically: Vertical = BiasAlignment.Vertical(0f)
@Stable
val Bottom: Vertical = BiasAlignment.Vertical(1f)
// 横向布局参数,不常用,一般用在布局参数中或在布局中使用
@Stable
val Start: Horizontal = BiasAlignment.Horizontal(-1f)
@Stable
val CenterHorizontally: Horizontal = BiasAlignment.Horizontal(0f)
@Stable
val End: Horizontal = BiasAlignment.Horizontal(1f)
}
}
/**
* 在不确定布局方向时,常用的对齐集合
*/
object AbsoluteAlignment {
// 以下是我们常用的变量参数,常与Modifier.align()使用
@Stable
val TopLeft: Alignment = BiasAbsoluteAlignment(-1f, -1f)
@Stable
val TopRight: Alignment = BiasAbsoluteAlignment(1f, -1f)
@Stable
val CenterLeft: Alignment = BiasAbsoluteAlignment(-1f, 0f)
@Stable
val CenterRight: Alignment = BiasAbsoluteAlignment(1f, 0f)
@Stable
val BottomLeft: Alignment = BiasAbsoluteAlignment(-1f, 1f)
@Stable
val BottomRight: Alignment = BiasAbsoluteAlignment(1f, 1f)
// 横向布局参数,不常用,一般用在布局参数中或在布局中使用
@Stable
val Left: Alignment.Horizontal = BiasAbsoluteAlignment.Horizontal(-1f)
@Stable
val Right: Alignment.Horizontal = BiasAbsoluteAlignment.Horizontal(1f)
}
/**
* 位置偏移数据类
* 根据传入的横纵位置参数,计算出布局中子控件的位置
*
*/
@Immutable
data class BiasAlignment(
val horizontalBias: Float,
val verticalBias: Float
) : Alignment {
/**
* align()方法计算出x,y的位置偏移量
* 主要是根据传进来的值:horizontalBias,verticalBias
* 根据上面常量传参可知,
* 顶部左对齐(-1, -1)横、纵都是-1,代入方法中结果得:(0,0)
* 顶部居中(0, -1),代入方法中结果得:(centerX,0),正好x是居中位置
* 顶部右对刘(1, -1),代入方法中结果得:(centerX * 2,0),正好x是右对齐
*/
override fun align(
size: IntSize,
space: IntSize,
layoutDirection: LayoutDirection
): IntOffset {
val centerX = (space.width - size.width).toFloat() / 2f
val centerY = (space.height - size.height).toFloat() / 2f
val resolvedHorizontalBias = if (layoutDirection == LayoutDirection.Ltr) {
horizontalBias
} else {
-1 * horizontalBias
}
val x = centerX * (1 + resolvedHorizontalBias)
val y = centerY * (1 + verticalBias)
return IntOffset(x.roundToInt(), y.roundToInt())
}
/**
* 见:align()说明,这里只是上面的其中一种情况
*/
@Immutable
data class Horizontal(private val bias: Float) : Alignment.Horizontal {
override fun align(size: Int, space: Int, layoutDirection: LayoutDirection): Int {
val center = (space - size).toFloat() / 2f
val resolvedBias = if (layoutDirection == LayoutDirection.Ltr) bias else -1 * bias
return (center * (1 + resolvedBias)).roundToInt()
}
}
/**
* 见:align()说明,这里只是上面的其中一种情况
*/
@Immutable
data class Vertical(private val bias: Float) : Alignment.Vertical {
override fun align(size: Int, space: Int): Int {
val center = (space - size).toFloat() / 2f
return (center * (1 + bias)).roundToInt()
}
}
}
/**
* 绝对位置偏移类
* 和BiasAlignment算法一样
*/
@Immutable
data class BiasAbsoluteAlignment(
private val horizontalBias: Float,
private val verticalBias: Float
) : Alignment {
override fun align(size: IntSize, space: IntSize, layoutDirection: LayoutDirection): IntOffset {
// Convert to Px first and only round at the end, to avoid rounding twice while calculating
// the new positions
val remaining = IntSize(space.width - size.width, space.height - size.height)
val centerX = remaining.width.toFloat() / 2f
val centerY = remaining.height.toFloat() / 2f
val x = centerX * (1 + horizontalBias)
val y = centerY * (1 + verticalBias)
return IntOffset(x.roundToInt(), y.roundToInt())
}
@Immutable
data class Horizontal(private val bias: Float) : Alignment.Horizontal {
override fun align(size: Int, space: Int, layoutDirection: LayoutDirection): Int {
val center = (space - size).toFloat() / 2f
return (center * (1 + bias)).roundToInt()
}
}
}