Compose 可组合项 - 布局类

组合函数不指定布局默认是Box堆叠。一些概念参考View版的ContraintLayout

一、纵向 Colum

inline fun Column(

modifier = Modifier,

verticalArrangement = Arrangement.Top,        //子元素纵向排列规则

horizontalAlignment = Alignment.Start,        //子元素横向排列规则

content: @Composable ColumnScope.() -> Unit

)

1.1 使Column具备滑动能力

val scrollState = rememberScrollState()
Column(Modifier.verticalScroll(scrollState)) {
    repeat(20) {
        Text(text = "aaaaaaa")
    }
}

二、横向 Row

inline fun Row(

modifier: Modifier = Modifier,

horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,

verticalAlignment: Alignment.Vertical = Alignment.Top,

content: @Composable RowScope.() -> Unit

)

三、堆叠 Box

inline fun Box(

modifier: Modifier = Modifier,

contentAlignment: Alignment = Alignment.TopStart,

propagateMinConstraints: Boolean = false,

content: @Composable BoxScope.() -> Unit

)

fun Box(modifier: Modifier)

四、约束布局 ConstraintLayout

查看官方最新版本

implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"

各种对齐或嵌套过深的时候使用。需要注意以下几点:

  • 通过 createRefs( ) 或 createRefFor( ) 为子元素创建引用(相当于创建ID)。
  • 通过 Modifier.constranAs( ) 将组合函数和引用绑定,在Lambda中指定约束条件。
  • 约束条件通过 linkTo( ) 或其它有用的方法指定。
  • parent 是现有的引用,可用于指定对 ConstraintLayout 本身的约束条件。
  • 默认尽可能小的容纳完子元素(wrap_content),设置子元素位置(gravity)依据的是内容宽高,若要相对于屏幕位置,需要对 ConstraintLayout 使用 Modifier.fillMaxWidth() 或 fillMaxHeight() 或fillMAxSize()。
  • 默认允许子元素超出屏幕,宽度要设置Dimension.preferredWrapContent。
@Composable
inline fun ConstraintLayout(
    modifier: Modifier = Modifier,
    optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
    crossinline content: @Composable ConstraintLayoutScope.() -> Unit
)
fun Modifier.constrainAs(
    ref: ConstrainedLayoutReference,    //指定绑定的引用
    //提供现有参数start、top、end、bottom表示当前组合函数的上下左右四边,调用linkTo()指定该边的约束
    constrainBlock: ConstrainScope.() -> Unit    //设置约束条件
)
fun linkTo(
    //指定连接到哪里,parent指ConstraintLayout(如)
    anchor: ConstraintLayoutBaseScope.***Anchor,
    margin: Dp = 0.dp,
    goneMargin: Dp = 0.dp
)

 

@Composable
fun MyConstraintLayout() {
    ConstraintLayout {
        //为每个子元素创建引用
        val (buttonRef, textRef) = createRefs()
        Button(
            onClick = { /* Do something */ },
            //将组合函数和引用关联
            modifier = Modifier.constrainAs(buttonRef) {
                //指定约束条件,现有引用parent是指ConstraintLayout
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }
        Text(
            text = "Text",
            Modifier.constrainAs(textRef) {
                top.linkTo(buttonRef.bottom, margin = 16.dp)
                //centerAround(button1.end)    //自己中间对齐谁的哪边
                centerHorizontallyTo(parent)    //水平居中
            }
        )
    }
}

4.1 栅栏 Barrier 

@Composable
fun MyBarrier() {
    ConstraintLayout {
        val (button1, button2, text) = createRefs()
        Button(onClick = { }, modifier = Modifier.constrainAs(button1) {
            top.linkTo(parent.top, margin = 16.dp)
        }) {
            Text(text = "Button1")
        }
        Text(text = "Text", modifier = Modifier.constrainAs(text) {
            top.linkTo(button1.bottom, margin = 16.dp)
            centerAround(button1.end)    //自己中间对齐谁的哪边
        })
        val barrier = createEndBarrier(button1, text)   //将button1和text组合成一个Barrier
        Button(onClick = { }, modifier = Modifier.constrainAs(button2) {
            top.linkTo(parent.top, margin = 16.dp)
            start.linkTo(barrier)
        }) {
            Text(text = "Button2")
        }
    }
}

4.2 基准线 Guideline

createGuidelineFromTop(offset: Dp)
createGuidelineFromBottom(offset: Dp)

createGuidelineFromStart(offset: Dp)

createGuidelineFromEnd(offset: Dp)

上下左右基于父布局的偏移量

createGuidelineFromTop(fraction: Float)
createGuidelineFromBottom(fraction: Float)

createGuidelineFromStart(fraction: Float)

createGuidelineFromEnd(fraction: Float)

上下左右基于父布局的百分比
createGuidelineFromAbsoluteLeft(offset: Dp)
createGuidelineFromAbsoluteLeft(fraction: Float)
createGuidelineFromAbsoluteRight(offset: Dp)
createGuidelineFromAbsoluteRight(fraction: Float)
国际化
Dimension.preferredWrapContent布局大小根据内容设置,并受布局约束影响。
Dimension.wrapContent        默认值布局大小只根据内容设置,不受布局约束影响。
Dimension.fillToConstraints布局大小将展开填充由布局约束所限制的空间。
Dimension.preferredValue布局大小是一个默认值,并受布局约束影响。
Dimension.value布局大小是一个默认值,不受布局约束影响。
Dimension.preferredWrapContent.adLast(100.dp)
Dimension.preferredWrapContent.atMost(100.dp)
可组合设置布局大小,设置最大/最小布局大小。

@Composable
fun MyGuideline() {
    ConstraintLayout {
        val text = createRef()
        val guideline = createGuidelineFromStart(fraction = 0.5f)
        Text(
            text = "Hellow Wodr!Hellow Wodr!Hellow Wodr!Hellow Wodr!Hellow Wodr!Hellow Wodr!Hellow Wodr!",
            modifier = Modifier.constrainAs(text) {
                linkTo(start = guideline, end = parent.end)
                //默认允许子元素超出屏幕,所以这里要设置一下
                width = Dimension.preferredWrapContent
            }
        )
    }
}

4.3 链 Chain

fun createHorizontalChain(

        vararg elements: ConstrainedLayoutReference,        //需要打包在一起的子元素引用
        chainStyle: ChainStyle = ChainStyle.Spread        //链的类型

)

fun createVerticalChain(
        vararg elements: ConstrainedLayoutReference,
        chainStyle: ChainStyle = ChainStyle.Spread
)
ChainStyle.Spread        默认所有子元素平均分布在父布局中
ChainStyle.SpreadInside头尾子元素分布在两端,其余平均分布剩下空间。
ChainStyle.Packed所有子元素打包在一起,放在链条中间。

@Composable
fun MyChain() {
    ConstraintLayout(modifier = Modifier.fillMaxSize()) {
        val (box1, box2, box3) = createRefs()
        createHorizontalChain(box1, box2, box3, chainStyle = ChainStyle.Spread)
        Box(modifier = Modifier.size(100.dp).background(Color.Red).constrainAs(box1) {})
        Box(modifier = Modifier.size(100.dp).background(Color.Green).constrainAs(box2) {})
        Box(modifier = Modifier.size(100.dp).background(Color.Blue).constrainAs(box3) {})
    }
}

4.4 约束集解耦 ConstraintSet

上面约束都是写在子元素里的,可以抽取出来在外部定义,通过传参的方式解耦,即动态约束。

  1. 创建 ConstraintSet(定义引用和对应的约束条件)传给 ConstraintLayout。
  2. 子元素通过 Modifier.layourId() 设置为 ConstraintSet 中对应的引用。

@Composable
fun Before() {
    val margin = 16.dp
    ConstraintLayout {
        val (button, text) = createRefs()
        Button(onClick = {}, modifier = Modifier.constrainAs(button) {
            top.linkTo(parent.top, margin = margin)
        }) {
            Text(text = "Button")
        }
        Text(text = "Text", modifier = Modifier.constrainAs(text) {
            top.linkTo(button.bottom, margin = margin)
        })
    }
}
//外部定义约束集
private fun myContraints(margin: Dp) = ConstraintSet {
    //创建引用
    val button = createRefFor(id = "button")
    val text = createRefFor(id = "text")
    //配置约束条件
    constrain(button) {
        top.linkTo(parent.top, margin)
    }
    constrain(text) {
        top.linkTo(button.bottom, margin)
    }
}
@Composable
fun after() {
    //该组合项提供的现有参数可用来根据可用空间调用不同的可组合项(屏幕适配)
    //单位dp的参数:minWidth、minHeight、maxWidth、maxHeight
    //单位px的参数:constraints.maxWidth
    BoxWithConstraints {
        //根据竖屏横屏返回不同的值
        val margin = if (maxWidth < maxHeight) myContraints(16.dp) else myContraints(20.dp)
        //传入约束集使用
        ConstraintLayout(margin) {
            //子元素设置约束集中对应的引用
            Button(onClick = {}, modifier = Modifier.layoutId("button")) {
                Text(text = "Button")
            }
            Text(text = "Text", modifier = Modifier.layoutId("text"))
        }
    }
}

五、脚手架 Scaffold

槽位(Slots API)会在界面中留出空位,让开发者自行填充使用。Scaffold可以为最常见的Material组件提供槽位(TopAppBar、BottomAppBar、FloatingActionBar、Drawer),使它们得到适当放置且正确的协同工作。

fun Scaffold(
    modifier = Modifier,
    scaffoldState = rememberScaffoldState(),    //脚手架的状态(例如控件抽屉是否打开)
    topBar = {},        //顶部标题栏,通常是一个TopAppBar
    bottomBar = {},        //底部导航栏,通常是一个BottomNavigation
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },    //用来展示SnackBar
    floatingActionButton = {},        //悬浮按钮
    floatingActionButtonPosition = FabPosition.End,        //悬浮按钮位置
    isFloatingActionButtonDocked = false,    //如果存在BottomBar,那么是否与BottomBar重叠一半的高度
    drawerContent = null,    //抽屉的内容
    drawerGesturesEnabled = true,    //否允许手势控制抽屉的打开和关闭
    drawerShape = MaterialTheme.shapes.large,    //抽屉的形状
    drawerElevation = DrawerDefaults.Elevation,    //抽屉的阴影高度
    drawerBackgroundColor = MaterialTheme.colors.surface,    //抽屉的背景色
    drawerContentColor = contentColorFor(drawerBackgroundColor),    //抽屉内容的背景色
    drawerScrimColor = DrawerDefaults.scrimColor,    //抽屉组件打开时屏幕剩余部分的遮盖颜色
    backgroundColor = MaterialTheme.colors.background,    //脚手架的背景色
    contentColor = contentColorFor(backgroundColor),        //脚手架内容背景色
    content: @Composable (PaddingValues) -> Unit    //脚手架的内容
)

5.1 标题栏 TopBar

fun TopAppBar(
    title: @Composable () -> Unit,    //标题区域
    modifier: Modifier = Modifier,
    navigationIcon: @Composable () -> Unit = {},    //左侧导航图标区域,一般为IconButton或IconToggleButton
    actions: @Composable RowScope.() -> Unit = {},    //右侧菜单区域,默认布局是Row,一般为IconButton
    windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,    //将尊重的窗口嵌入
    colors: TopAppBarColors = TopAppBarDefaults.smallTopAppBarColors(),    //用于不同状态下使用的颜色
    scrollBehavior: TopAppBarScrollBehavior? = null    //针对滚动的偏移设置
)

5.2 导航栏 BottomBar

fun BottomNavigation(
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,    //背景色
    contentColor: Color = contentColorFor(backgroundColor),    //内容颜色
    elevation: Dp = BottomNavigationDefaults.Elevation,    //高度
    content: @Composable RowScope.() -> Unit    //包裹的内容
)
fun RowScope.BottomNavigationItem(
    selected: Boolean,    //是否选中
    onClick: () -> Unit,    //点击事件
    icon: @Composable () -> Unit,    //图标
    modifier: Modifier = Modifier,
    enabled: Boolean = true,    //是否可点击
    label: @Composable (() -> Unit)? = null,    //名称
    alwaysShowLabel: Boolean = true,    //名称是否一直显示
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    selectedContentColor: Color = LocalContentColor.current,    //选中时文本标签和图标的颜色以及波纹的颜色
    unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)    //未选中时文本标签和图标的颜色
)

5.3 抽屉栏 Drawer

5.4 悬浮按钮 FloatingActionBar

5.5 SnackBar

Snackbar(
    modifier: Modifier = Modifier,//布局修饰
    action: @Composable (() -> Unit)? = null,//动作
    actionOnNewLine: Boolean = false,//action是否应该放在单独的行上
    shape: Shape = MaterialTheme.shapes.small,//Snackbar的形状和阴影  
    backgroundColor: Color = SnackbarDefaults.backgroundColor,//背景颜色
    contentColor: Color = MaterialTheme.colors.surface,//内容颜色
    elevation: Dp = 6.dp,//阴影效果
    content: @Composable () -> Unit//内容
)
Snackbar(
    snackbarData: SnackbarData,//通过SnackbarHostState显示的关于当前snackbar的数据
    modifier: Modifier = Modifier,//布局修饰
    actionOnNewLine: Boolean = false,//action是否应该放在单独的行上
    shape: Shape = MaterialTheme.shapes.small,//Snackbar的形状和阴影  
    backgroundColor: Color = SnackbarDefaults.backgroundColor,//背景颜色
    contentColor: Color = MaterialTheme.colors.surface,//内容颜色
    actionColor: Color = SnackbarDefaults.primaryActionColor,//动作颜色
    elevation: Dp = 6.dp//阴影效果
) 

5.6 内容

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值