当前位置:   article > 正文

Android的Compose_android compose

android compose

Jetpack Compose 是用于构建原生 Android 界面的新工具包,无需修改任何 XML 布局,也不需要使用布局编辑器。相反,只需调用可组合函数来定义所需的元素,Compose 编译器即会完成后面的所有工作。

简而言之,使用Compose,不再需要xml编写页面。


可组合函数(Composable function)

Compose是围绕可组合函数构建的,只需要描述应用界面的外观并提供数据依赖,而不必关注界面的构建过程(如初始化元素、将其附加到父项等)。而创建Composable function,只需要添加注解@Composable到函数名称前。

首先,我们构建创建一个应用:ComposeTutorial。在AS中选择Empty Activity创建。

添加文本元素

  1. class MainActivity : ComponentActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContent {//在此处定义布局
  5. //此处的Text方法是由Compose界面库定义的文本Composable function
  6. Text("Hello world!")
  7. }
  8. }
  9. }

setContent块定义了activity的布局,在此处我们添加了Text即“Hello World!”。

自定义可组合函数

如果需要将一个函数转换为Composable function,我们需要添加注解“@Composable”。

修改MainActivity:

  1. class MainActivity : ComponentActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContent {
  5. MessageCard("Android")//使用我们自定义的Composable function
  6. }
  7. }
  8. }
  9. @Composable//添加注解,使该函数成为Composable function
  10. fun MessageCard(name: String) {
  11. Text(text = "Hello $name!")
  12. }

在AS中预览Composable function

借助@Preview注解,可以在AS中预览Composable function,无需安装到设备或虚拟器中。

唯一要求是该注解不能用于接收参数的函数中,因此在MainActivity新增如下函数:

  1. @Preview
  2. @Composable
  3. fun PreviewMessageCard() {
  4. MessageCard("Android")
  5. }

在重新构建后,该函数没有被调用,应用本身不会改变,但是AS对于所有添加了@Preview注解的界面元素可以进行预览,点击如下两个按钮之一即可:


布局(Layout)

在此处我们实现一个简单的聊天界面,显示发送者和消息内容,点击消息时可缩放。

添加多个文本

  1. class MainActivity : ComponentActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContent {
  5. //向Composable function中传入发送者名称和消息内容
  6. MessageCard(Message("Android", "Jetpack Compose"))
  7. }
  8. }
  9. }
  10. //新建一个Message类,包含消息发送者和消息内容
  11. data class Message(val author: String, val body: String)
  12. @Composable
  13. fun MessageCard(msg: Message) {
  14. Text(text = msg.author)
  15. Text(text = msg.body)
  16. }
  17. @Preview
  18. @Composable
  19. fun PreviewMessageCard() {
  20. MessageCard(
  21. msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
  22. )
  23. }

这段代码会在内容视图中创建两个文本元素。不过,由于未提供有关如何排列这两个文本元素的信息,因此它们会相互重叠,使文本无法阅读。

使用Column、Row、Box

Column,直译为“圆柱体、长列”。

使用该函数修改MessageCard,可以垂直排列元素,使其不再重叠文本。

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. Column {
  4. Text(text = msg.author)
  5. Text(text = msg.body)
  6. }
  7. }

同样的,可以使用Row函数水平排列元素,而使用Box函数可以堆叠元素。

添加图片元素

使用Resource Manager从照片库中导入图片,修改MessageCard:

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. //使用Row方法,水平排列图片和消息
  4. Row {
  5. Image(
  6. painter = painterResource(R.drawable.profile_picture),
  7. contentDescription = "Contact profile picture",
  8. )
  9. Column {
  10. Text(text = msg.author)
  11. Text(text = msg.body)
  12. }
  13. }
  14. }

配置布局(Modifier)

使用修饰符(Modifier)实现。

Compose中的每一个组件都具有Modifier属性,通过他我们可以设置组件的大小、间距、外观,甚至添加互动事件,如点击、触摸事件。

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. //在消息周围添加8dp的距离
  4. Row(modifier = Modifier.padding(all = 8.dp)) {
  5. Image(
  6. painter = painterResource(R.drawable.profile_picture),
  7. contentDescription = "Contact profile picture",
  8. modifier = Modifier
  9. //设置图片大小
  10. .size(40.dp)
  11. //将图片修剪为圆形
  12. .clip(CircleShape)
  13. )
  14. //在图片和消息之间添加一个水平的空间(Spacer),间距为8dp
  15. Spacer(modifier = Modifier.width(8.dp))
  16. Column {
  17. Text(text = msg.author)
  18. // 在发送者和消息内容之间添加一个垂直的空间
  19. Spacer(modifier = Modifier.height(4.dp))
  20. Text(text = msg.body)
  21. }
  22. }
  23. }

Material Design

Compose 旨在支持 Material Design 原则。它的许多界面元素都原生支持 Material Design。

使用

Jetpack Compose 原生提供 Material Design 3 及其界面元素的实现。我们使用 Material Design 样式改进MessageCard可组合项的外观。

在创建ComposeTutorial项目时,会同时创建一个名为“ComposeTutorialTheme”的Material主题,和一个来自Material Design 3的“Surface”。我们将用到这两位来封装MessageCard函数。

Material Design是围绕Color、Typography、Shape来构建的,我们将逐一添加这些元素。

修改MainActivity:

  1. class MainActivity : ComponentActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContent {
  5. //使用ComposeTutorialTheme和Surface封装MessageCard函数
  6. ComposeTutorialTheme {
  7. //将给定的组件或布局填满父容器的界面
  8. Surface(modifier = Modifier.fillMaxSize()) {
  9. MessageCard(Message("Android", "Jetpack Compose"))
  10. }
  11. }
  12. }
  13. }
  14. }
  15. @Preview
  16. @Composable
  17. fun PreviewMessageCard() {
  18. //在@Preview中也要封装,沿用应用主题中定义的样式,保持统一
  19. ComposeTutorialTheme {
  20. Surface {
  21. MessageCard(
  22. msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
  23. )
  24. }
  25. }
  26. }

颜色

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. Row(modifier = Modifier.padding(all = 8.dp)) {
  4. Image(
  5. painter = painterResource(R.drawable.profile_picture),
  6. contentDescription = null,
  7. modifier = Modifier
  8. .size(40.dp)
  9. .clip(CircleShape)
  10. //为图像增加一个圆框
  11. .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
  12. )
  13. Spacer(modifier = Modifier.width(8.dp))
  14. Column {
  15. Text(
  16. text = msg.author,
  17. //通过MaterialTheme.colorScheme,使用已封装主题中的颜色设置样式
  18. color = MaterialTheme.colorScheme.secondary
  19. )
  20. Spacer(modifier = Modifier.height(4.dp))
  21. Text(text = msg.body)
  22. }
  23. }
  24. }

Typography(排版)

MaterialTheme 中提供了 Material Typography 样式,只需将其添加到 Text 可组合项中即可。

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. Row(modifier = Modifier.padding(all = 8.dp)) {
  4. Image(
  5. painter = painterResource(R.drawable.profile_picture),
  6. contentDescription = null,
  7. modifier = Modifier
  8. .size(40.dp)
  9. .clip(CircleShape)
  10. .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
  11. )
  12. Spacer(modifier = Modifier.width(8.dp))
  13. Column {
  14. Text(
  15. text = msg.author,
  16. color = MaterialTheme.colorScheme.secondary,
  17. style = MaterialTheme.typography.titleSmall
  18. )
  19. Spacer(modifier = Modifier.height(4.dp))
  20. Text(
  21. text = msg.body,
  22. style = MaterialTheme.typography.bodyMedium
  23. )
  24. }
  25. }
  26. }

Shape(形状)

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. Row(modifier = Modifier.padding(all = 8.dp)) {
  4. Image(
  5. painter = painterResource(R.drawable.profile_picture),
  6. contentDescription = null,
  7. modifier = Modifier
  8. .size(40.dp)
  9. .clip(CircleShape)
  10. .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
  11. )
  12. Spacer(modifier = Modifier.width(8.dp))
  13. Column {
  14. Text(
  15. text = msg.author,
  16. color = MaterialTheme.colorScheme.secondary,
  17. style = MaterialTheme.typography.titleSmall
  18. )
  19. Spacer(modifier = Modifier.height(4.dp))
  20. //将消息详情封装在Surface中,此时可自定义消息详情的大小、形状等布局
  21. Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
  22. Text(
  23. text = msg.body,
  24. modifier = Modifier.padding(all = 4.dp),
  25. style = MaterialTheme.typography.bodyMedium
  26. )
  27. }
  28. }
  29. }
  30. }

启用深色主题

又称夜间模式。由于支持Material Design,Jetpack Compose默认能够处理深色主题。

使用Material Design颜色、文本和背景时,系统会自动适应深色背景。

  1. //可以在文件中以单独函数的形式创建多个预览,也可以向同一个函数中添加多个注解
  2. @Preview(name = "Light Mode")
  3. @Preview(
  4. uiMode = Configuration.UI_MODE_NIGHT_YES,
  5. showBackground = true,
  6. name = "Dark Mode"
  7. )
  8. @Composable
  9. fun PreviewMessageCard() {
  10. ComposeTutorialTheme {
  11. Surface {
  12. MessageCard(
  13. msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
  14. )
  15. }
  16. }
  17. }


列表和动画

创建消息列表(LazyColumn、LazyRow)

LazyColumn、LazyRow是Compose常见的两个组件,他们的优点是可以延迟加载。他们只会加载当前可见的列表项,并在滚动时动态回收其他项,这使得他们适用于展示大量数据或无限滚动的列表。

在使用中,会包含一个items子项。他接受LIst作为参数,并且其lambda会接收到参数。系统会针对提供的List的每个项调用此lambda。

  1. @Composable
  2. fun Conversation(messages: List<Message>) {
  3. LazyColumn {
  4. //items子项
  5. items(messages) { message ->
  6. MessageCard(message)
  7. }
  8. }
  9. }
  10. @Preview
  11. @Composable
  12. fun PreviewConversation() {
  13. ComposeTutorialTheme {
  14. Conversation(SampleData.conversationSample)
  15. }
  16. }

在展开消息时显示动画效果

为了存储某条消息是否已展开,我们使用remember和mutableStateOf函数。

可组合函数可以使用remember将本地状态存储到内存中,并跟踪传递给mutableStateOf的值的变化。而mutableStateOf函数可以在可组合函数内部创建一个可变的状态,并将其与UI组件进行绑定。当状态值发生变化时,Compose会自动重绘相关的组件。

  1. class MainActivity : ComponentActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContent {
  5. ComposeTutorialTheme {
  6. Conversation(SampleData.conversationSample)
  7. }
  8. }
  9. }
  10. }
  11. @Composable
  12. fun MessageCard(msg: Message) {
  13. Row(modifier = Modifier.padding(all = 8.dp)) {
  14. Image(
  15. painter = painterResource(R.drawable.profile_picture),
  16. contentDescription = null,
  17. modifier = Modifier
  18. .size(40.dp)
  19. .clip(CircleShape)
  20. .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
  21. )
  22. Spacer(modifier = Modifier.width(8.dp))
  23. // 在此变量中,跟踪当前消息是否展开
  24. var isExpanded by remember { mutableStateOf(false) }
  25. // 当点击该消息时,改变展开状态
  26. Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
  27. Text(
  28. text = msg.author,
  29. color = MaterialTheme.colorScheme.secondary,
  30. style = MaterialTheme.typography.titleSmall
  31. )
  32. Spacer(modifier = Modifier.height(4.dp))
  33. Surface(
  34. shape = MaterialTheme.shapes.medium,
  35. shadowElevation = 1.dp,
  36. ) {
  37. Text(
  38. text = msg.body,
  39. modifier = Modifier.padding(all = 4.dp),
  40. // 若展开,全部显示;不展开,最大显示一行
  41. maxLines = if (isExpanded) Int.MAX_VALUE else 1,
  42. style = MaterialTheme.typography.bodyMedium
  43. )
  44. }
  45. }
  46. }
  47. }

注:需要添加以下导入内容才能正确使用 Kotlin 的委托属性语法(by 关键字):
import androidx.compose.runtime.getValue

import androidx.compose.runtime.setValue

使用by关键字是避免每次都访问value属性的好方法。

同时需要注意的是,我们应该只在可组合函数的作用域之外改变状态。这是因为可组合项可以频繁运行、且以任何顺序执行。​​​​​​​此处我们可以在clickable中修改isExpanded的值,是因为clickable不是可组合函数。

除了remember关键字,我们还可以使用rememberSaveable,它与前者类似,但存储的值可以在重新创建activity和进程后保存下来。需要注意的是,rememberSaveable适用于UI状态,如购物车的商品数量或选定的标签页,但不适用于过渡动画状态等。

同时我们可以加入颜色,在消息缩放时改变消息的颜色。但不能只是简单的改变消息的背景颜色,我们应当加入动画,使得变化时逐步更改。

相同的,在点击缩放时,我们也可以加上动画,使得缩放更加顺滑。

  1. @Composable
  2. fun MessageCard(msg: Message) {
  3. Row(modifier = Modifier.padding(all = 8.dp)) {
  4. Image(
  5. painter = painterResource(R.drawable.profile_picture),
  6. contentDescription = null,
  7. modifier = Modifier
  8. .size(40.dp)
  9. .clip(CircleShape)
  10. .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
  11. )
  12. Spacer(modifier = Modifier.width(8.dp))
  13. var isExpanded by remember { mutableStateOf(false) }
  14. // 该变量会逐步更新颜色,animateColorAsState函数实现颜色之间的过渡动画效果
  15. val surfaceColor by animateColorAsState(
  16. if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
  17. )
  18. Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
  19. Text(
  20. text = msg.author,
  21. color = MaterialTheme.colorScheme.secondary,
  22. style = MaterialTheme.typography.titleSmall
  23. )
  24. Spacer(modifier = Modifier.height(4.dp))
  25. Surface(
  26. shape = MaterialTheme.shapes.medium,
  27. shadowElevation = 1.dp,
  28. color = surfaceColor,
  29. //加入animateContentSize,给缩放加入动画,更加顺滑
  30. modifier = Modifier.animateContentSize().padding(1.dp)
  31. ) {
  32. Text(
  33. text = msg.body,
  34. modifier = Modifier.padding(all = 4.dp),
  35. maxLines = if (isExpanded) Int.MAX_VALUE else 1,
  36. style = MaterialTheme.typography.bodyMedium
  37. )
  38. }
  39. }
  40. }
  41. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/816275
推荐阅读
相关标签
  

闽ICP备14008679号