Android前沿技术学习——Compose布局原理+配置布局+四大块技术全方面解析

本文深入介绍了Android的Jetpack Compose布局系统,涵盖可组合函数、标准布局元素、Material组件和自定义布局的详细解析。Compose通过避免多次测量实现了高性能,允许深度嵌套而不会影响性能。文章详细阐述了Compose的布局模型、修饰符、槽位布局,以及Material组件如Scaffold、悬浮操作按钮和信息提示控件的使用。同时,还讨论了ConstraintLayout在Compose中的应用,展示了如何使用自定义布局和固有特性测量。
摘要由CSDN通过智能技术生成

一、简介

布局系统的 Jetpack Compose 实现有两个主要目标:一是实现高性能,二是让开发者能够轻松编写自定义布局。在 Compose 中,通过避免多次测量布局子级可实现高性能。如果需要进行多次测量,Compose 具有一个特殊系统,即固有特性测量。

注意:使用 Android View 系统时,在嵌套某些 View(如 RelativeLayout)时,可能会出现一些性能问题。由于 Compose 可以避免多次测量,因此可以根据需要进行深层次嵌套,而不会影响性能。

布局主要包括:布局基础知识、Material组件和布局、自定义布局、Compose中使用ConstraintLayout。

img

二、布局基础

img

可组合函数

可组合函数是 Compose 的基本构建块,返回值是 Unit 的函数,用于描述界面中的某一部分,该函数可接收参数。
组合函数中可包含多个界面元素。
其基本格式为:

@Composable
fun xxx():Unit{
   
....
}
标准布局元素

在Compose中标准的布局元素有三个:BoxColumnRow

img

标准布局元素特性示意图

Box
重叠布局,类似Android View系统中的FramLayout布局,元素会重叠显示,其原型定义如下:

@Composable
inline fun Box(
    modifier: Modifier = Modifier,                   //修饰符
    contentAlignment: Alignment = Alignment.TopStart,//内容的位置
    propagateMinConstraints: Boolean = false,       //是否应将传入的最小约束传递给内容
    content: @Composable BoxScope.() -> Unit    //内容,即界面元素
) {
   
    ......
}

例子

/**
 * 标准布局 - Box
 */
@Composable
fun BoxExample(){
   
    Box (
        modifier = Modifier.size(width = 230.dp,height = 100.dp),
        contentAlignment = Alignment.Center
    ){
     //对应content参数 lambda表达上
        Text(text = "Text 1")
        Text(text = "Text 2")
    }
}

img

预览结果

Column
垂直布局,在界面元素垂直方向依次排列。源码中定义如下:

@Composable
inline fun Column(
    modifier: Modifier = Modifier,          //修饰符
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,  //内容元素垂直方向分布方式
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,    //内容元素水平方向分布方式
    content: @Composable ColumnScope.() -> Unit                      //内部元素
) {
   
    ......
}

实例

/**
 * 标准布局 - Column
 */
@Composable
fun ColumnExample(){
   
    Column (
        modifier = Modifier.size(width = 230.dp,height = 100.dp),
        verticalArrangement = Arrangement.Center,//垂直方向居中
        horizontalAlignment = Alignment.End      //水平方向靠右
    ){
     //对应content参数 lambda表达上
        Text(text = "Text 111")
        Text(text = "Text 666666")
    }
}

img

Column示例预览结果

Row
元素水平方向分布,源码中定义:

@Composable
inline fun Row(
    modifier: Modifier = Modifier,          //修饰符
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,//水平方向排列方式
    verticalAlignment: Alignment.Vertical = Alignment.Top,      //垂直方向元素排列方式
    content: @Composable RowScope.() -> Unit          //内部子元素
) {
   
    ......
}

示例

/**
 * 标准布局 - Row
 */
@Composable
fun RowExample(){
   
    Row (
        modifier = Modifier.size(width = 230.dp,height = 100.dp),
        horizontalArrangement = Arrangement.SpaceAround,
        verticalAlignment = Alignment.Bottom
    ){
     //对应content参数 lambda表达上
        Text(text = "Text 111")
        Text(text = "Text 666666")
    }
}

img

Row示例预览

基本组件

Jetpack Compose中组件库包括:compose-ui和material。很多常用基本组件都是在material库中,Compose-ui中组件很少:Image、BasicTextField(输入框)。
示例:

//添加一个图片
Image(
      //填充内容
      painter = painterResource(id = message.iconId),
      contentDescription = "logo",
      //尺寸及形状
      modifier= Modifier
          .padding(top = 2.dp)
          .size(40.dp)             //图像尺寸
          .clip(CircleShape)       //形状
          .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)//边框样式
  )
布局模型

在对标准布局元素和组件有了一定了解后,我们来看下Compose的布局流程。
首先Compose布局是一个界面树,从树的根节点开始依次要求其子节点对自身进行测量,然后递归完成所有子节点的测量,并将约束条件沿着树向下传递给子节点,并将测量的尺寸和放置指令依次向根节点传递。

以下面可组合函数为示例:

@Composable
fun SearchResult(...) {
   
  Row(...) {
   
    Image(...)
    Column(...) {
   
      Text(...)
      Text(..)
    }
  }
}

其布局过程如下图示:

img

image.png

修饰符

在Compose布局中修饰符至关重要,您可以使用修饰符来修饰或扩充可组合项。常用的修饰符如下:

  • background 可组合元素的背景色;
  • clickable 使可组合项响应用户点击,并显示波纹效果;
  • padding 设置元素周围留出空间;
  • size 可组合元素的尺寸;
  • clip 可组合元素的形状;
  • border 可组合元素的边框及形状;
  • fillMaxSize可组合元素尺寸按父布局的最大尺寸显示;
  • fillMaxWidth 可组合元素宽度按父布局的最大宽度显示;
  • fillMaxHeight 可组合元素高度按父布局的最大高度显示;
    除以上外,还有widthheightwrapConentHeight等,用到的时候可以尝试看看效果。
    下面展示一个圆形图像的示例
/**
 * 修饰符使用示例
 */
@Composable
fun ModifierExample(){
   
    //添加一个图片
    Image(
        //填充内容
        painter = painterResource(id = R.mipmap.ic_girl),
        contentDescription = "logo",
        //尺寸及形状
        modifier= Modifier
            .padding(top = 2.dp)
            .background(Color.Blue)//设置蓝色背景
            .size(40.dp)             //图像尺寸
            .clip(CircleShape)       //圆形形状
            .border(1.5.dp, MaterialTheme.colors.secondary, CircleShape)//边框样式
    )
}

效果如下:

img

修饰符示例

修饰符扩展
除了使用Compose提供的修饰符外,我们也可以扩展函数自定义修饰符,具体方式可以参考Jetpack Compose布局(三)一文中讲的扩展布局修饰符

强调:修饰符的使用是有顺序的
强调:修饰符的使用是有顺序的
强调:修饰符的使用是有顺序的
例如,将上例的background和padding顺序调换下,就会如下图效果,仔细看两图的顶部边距,会发现区别

img

调换background和padding顺序的效果图

槽位布局

Compose中提供了固定槽位的可组合项,以简化界面元素,这些主要在androidx.compose.material:material库中,如:DrawerFloatingActionButtonTopAppBar等。
Material 组件大量使用槽位 API,这是 Compose 引入的一种模式,它在可组合项之上带来一层自定义设置。这种方法使组件变得更加灵活,因为它们接受可以自行配置的子元素,而不必公开子元素的每个配置参数。槽位会在界面中留出空白区域,让开发者按照自己的意愿来填充。如下图TopAppBar的槽位。

img

三、Material 组件和布局

Jetpack Compose 提供了 Material Design 的实现,后者是一个用于创建数字化界面的综合设计系统。Material 组件(按钮、卡片、开关等)和布局(如 Scaffold)可作为可组合函数提供。

img

Material 组件是用于创建界面的交互式构建块。Compose 提供了许多此类组件,开箱即可使用。如需了解提供了哪些组件,请参阅 Compose Material API 参考文档

Material 组件会使用应用中 MaterialTheme 提供的值:

@Composable
fun MyApp() {
   
    MaterialTheme {
   
        // Material Components like Button, Card, Switch, etc.
    }
}

如需详细了解主题,请参阅“Compose 中的主题”指南

内容槽

支持内部内容(文本标签、图标等)的 Material 组件往往会提供“槽”(即接受可组合内容的通用 lambda),而且还会提供尺寸和内边距等公共常量,从而支持设置内部内容的布局,使之符合 Material 规范。

例如 Button

Button(
    onClick = {
    /* ... */ },
    // Uses ButtonDefaults.ContentPadding by default
    contentPadding = PaddingValues(
        start = 20.dp,
        top = 12.dp,
        end = 20.dp,
        bottom = 12.dp
    )
) {
   
    // Inner content including an icon and a text label
    Icon(
        Icons.Filled.Favorite,
        contentDescription = "Favorite",
        modifier = Modifier.size(ButtonDefaults.IconSize)
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text("Like")
}


img

图 1. 使用 content 槽和默认内边距的 Button(左),以及使用提供自定义 contentPaddingcontent 槽的 Button(右)。

Button 有一个通用 content 尾随 lambda 槽,该槽使用 RowScope 将内容可组合项的布局设为行。此外,它还有一个 contentPadding 参数,用于将内边距应用于内部内容。您可以使用通过 ButtonDefaults 提供的常量,也可以使用自定义值。

再比如 ExtendedFloatingActionButton

ExtendedFloatingActionButton(
    onClick = {
    /* ... */ },
    icon = {
   
        Icon(
            Icons.Filled.Favorite,
            contentDescription = "Favorite"
        )
    },
    text = {
    Text("Like") }
)

img

图 2. 使用 icon 槽和 text 槽的 ExtendedFloatingActionButton

ExtendedFloatingActionButton 有两个槽,分别针对 icontext 标签,而没有通用 content lambda。虽然每个槽都支持通用的可组合内容,但该组件会自行判断这些内部内容的布局方式。它会在内部处理内边距、对齐方式和大小。

Scaffold

Compose 提供了便捷的布局,用于将 Material 组件组合成常见的屏幕图案。可组合项(例如 Scaffold)提供了适用于各种组件和其他屏幕元素的槽。

屏幕内容

Scaffold 有一个通用 content 尾随 lambda 槽。lambda 会收到应该应用于内容根目录(例如,通过 Modifier.padding)的 PaddingValues 实例,以便偏移顶部栏和底部栏(如果存在的话)。

Scaffold(/* ... */) {
    contentPadding ->
    // Screen content
    Box(modifier = Modifier.padding(contentPadding)) {
    /* ... */ }
}

应用栏

Scaffold顶部应用栏底部应用栏提供了槽。系统将在内部处理可组合项的放置位置。

img

您可以使用 topBar 槽和 TopAppBar

Scaffold(
    topBar = {
   
        TopAppBar {
    /* Top app bar content */ }
    }
) {
   
    // Screen content
}

img

您可以使用 bottomBar 槽和 BottomAppBar

Scaffold(
    bottomBar = {
   
        BottomAppBar {
    /* Bottom app bar content */ }
    }
) {
   
    // Screen content
}

这些槽可用于 BottomNavigation 等其他 Material 组件。 此外,您还可以使用自定义可组合项 - 例如,查看 Owl 示例中的初始配置屏幕

悬浮操作按钮

img

Scaffold悬浮操作按钮提供了槽。

您可以使用 floatingActionButton 槽和 FloatingActionButton

Scaffold(
    floatingActionButton = {
   
        FloatingActionButton(onClick = {
    /* ... */ }) {
   
            /* FAB content */
        }
    }
) {
   
    // Screen content
}

注意floatingActionButton 槽接受任何可组合内容。例如,您可以将展开式悬浮操作按钮ExtendedFloatingActionButton 结合使用。

系统将在内部处理 FAB 可组合项的底部放置位置。您可以使用 floatingActionButtonPosition 参数来调整水平位置:

Scaffold(
    floatingActionButton = {
   
        FloatingActionButton(onClick = {
    /* ... */ }) {
   
            /* FAB content */
        }
    },
    // Defaults to FabPosition.End
    floatingActionButtonPosition = FabPosition.Center
) {
   
    // Screen content
}

如果您使用的是 Scaffold 可组合项的 bottomBar 槽,则可以使用 isFloatingActionButtonDocked 参数将悬浮操作按钮与底部应用栏重叠:

Scaffold(
    floatingActionButton = {
   
        FloatingActionButton(onClick = {
    /* ... */ }) {
   
            /* FAB content */
        }
    },
    // Defaults to false
    isFloatingActionButtonDocked = true,
    bottomBar = {
   
        BottomAppBar {
    /* Bottom app bar content */ }
    }
) {
   
    // Screen content
}

img

图 3. 使用 floatingActionButton 槽和 bottomBar 槽的 ScaffoldisFloatingActionButtonDocked 参数设为 false(顶部)和 true(底部)。

BottomAppBar 支持带有 cutoutShape 参数的 FAB 刘海屏,它接受任何 Shape。最好提供停靠组件所使用的同一 Shape。例如,FloatingActionButton 使用 MaterialTheme.shapes.small,并将 50% 的边角大小作为其 shape 参数的默认值:

Scaffold(
    floatingActionButton = {
   
        FloatingActionButton(onClick = {
    /* ... */ }) {
   
            /* FAB content */
        }
    },
    isFloatingActionButtonDocked = true,
    bottomBar = {
   
        BottomAppBar(
            // Defaults to null, that is, No cutout
            cutoutShape = MaterialTheme.shapes.small.copy(
                CornerSize(percent = 50)
            )
        ) {
   
            /* Bottom app bar content */
        }
    }
) {
   
  // Screen content
}

img

图 4. 具有 BottomAppBar 和停靠 FloatingActionButtonScaffoldBottomAppBar 的自定义 cutoutShapeFloatingActionButton 所使用的 Shape 一致。

信息提示控件

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值