Android Jetpack Compose初探

开始

什么是Compose

Jetpack Compose 谷歌推出的 UI 开发框架,目的是简化界面开发,无需在 XML 中定义 UI。该组件将响应式编程模型与简洁易用的 Kotlin 编程语言相结合,并采用完全声明式的代码编写方式,通过调用一系列函数来描述界面,这些函数会将数据转换为 UI 层次结构。当底层数据发生变化时,Compose 框架会自动重新执行这些函数,从而更新 UI。

总结来说,Android Compose 是一种“现代化”的 UI 开发框架,它通过声明式编程、可组合性、高效的状态管理和动画支持等特性,极大地简化了 Android 应用的界面开发工作,提升了代码质量和开发效率。

Hello Compose
创建项目

在这里插入图片描述
点击 Empty Activity 创建新项目,在Android Studio 2023.1.1 版本,默认创建的项目就是基于 Compose,所以无需进行特殊配置处理。

运行项目

官方 demo 实现的效果非常简单,就是一句 Hello Compose! ,接下来我们简单看一下代码是如何实现的。

查看代码
package com.example.composedemo

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.composedemo.ui.theme.ComposeDemoTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            // 应用主题
            ComposeDemoTheme {
                // 一个通用的布局容修饰或扩充可组合项器,可以设置背景色、形状
                Surface(
                    // 修饰或扩充可组合项
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greeting("Compose")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeDemoTheme {
        Greeting("Android")
    }
}

上述是 Android Studio 帮我们创建的默认项目,代码比较简单,关键地方也进行了注释。

@Composable 和 @Preview

需要注意的是 @Composable 和 @Preview 这两个注解,下面详细进行介绍。

@Composable

@Composable 是 Jetpack Compose 中的一个注解,它用于标记一个函数可以被 Compose 编译器用来构建 UI。这些函数被称为 Composable 函数,具有一下特点:

  • 可组合:Composable 函数可以调用其他 Composable 函数,这样可以组合多个 UI 组件来构建复杂的 UI。
  • 可重用:Composable 函数可以被多次调用,每次调用都会生成 UI 的一个独立实例。
  • 响应式:Composable 函数可以响应状态的变化,当状态变化时,只有依赖于这个状态的 Composable 函数会被重新调用,并且更新 UI。
@Preview

@Preview 是 Jetpack Compose 中的一个注解,它用于在 Android Studio 的预览窗口中显示 Composable 函数的预览。当你在 Composable 函数上添加 @Preview 注解时,Android Studio 会在设计模式下渲染该函数的 UI,并显示在预览窗口中。这样可以在不运行整个应用程序的情况下,快速查看和检查你的 Composable UI,具体效果如下图所示。

在这里插入图片描述

初探

View

首先先带大家了解一下 View 控件,以图文的形式进行示例。除了少部分控件与 Android 有些许差异,大部分都是一样的。下面会依次介绍我们常用的控件,比较简单请放心食用。

名称描述
Text用于显示文本
Image用于显示图片
TextField文本输入控件
Button用于创建按钮
Checkbox复选框控件
RadioButton单选按钮控件
LinearProgressIndicator水平进度条控件
Slider滑块控件
Text
@Composable
fun MTextView(modifier: Modifier = Modifier) {
    Text(
        text = "Hello Text !",
        fontSize = 36.sp,
        color = Color(0xFF121113),
        fontStyle = FontStyle.Italic,
        modifier = modifier
    )
}

Image
@Composable
fun ShowImage() {
    val image = painterResource(R.drawable.ic_launcher)
    Image(
        painter = image,
        contentDescription = "image",
        modifier = Modifier.padding(16.dp),
        contentScale = ContentScale.Crop,
        alignment = Alignment.Center
    )
}

TextField
@Composable
fun EditTextView() {
    val text = remember { mutableStateOf("") }
    TextField(
        value = text.value,
        onValueChange = { text.value = it },
        //提示文本,当输入框为空时显示
        placeholder = { Text("input user name", color = Color(0xFF666262)) },
        singleLine = true,
        maxLines = 1,
        textStyle = TextStyle(color = Color(0xFF111111), fontSize = 28.sp),
    )
}

Button
@Composable
fun ButtonView() {
    val context = LocalContext.current
    //创建一个协程
    val scope = rememberCoroutineScope()
    Button(onClick = {
        scope.launch {
            Toast.makeText(context, "This is Button", Toast.LENGTH_SHORT).show()
        }
    }, modifier = Modifier
        .size(200.dp, 100.dp)
        .padding(20.dp), enabled = true) {
        Text("Click Me", fontSize = 20.sp)
    }
}

Checkbox
@Composable
fun CheckboxView() {
    // 保存状态
    val state = remember { mutableStateOf(true) }
    Checkbox(
        checked = state.value,
        onCheckedChange = { state.value = it }
    )
}

RadioButton
@Composable
fun RadioButtonView() {
    // 默认保存选择MVVM
    val normal = remember { mutableStateOf("MVVM") }
    val options = listOf("MVVM", "MVP", "MVI", "MVC")

    Column {
        options.forEach { option ->
            Row(verticalAlignment = Alignment.CenterVertically) {
                RadioButton(
                    selected = normal.value == option,
                    onClick = { normal.value = option }
                )
                Text(
                    text = option,
                    modifier = Modifier.padding(start = 8.dp)
                )
            }
        }
    }
}

LinearProgressIndicator
@Composable
fun ProgressBarView() {
    val progress = remember { mutableFloatStateOf(0.8f) }
    LinearProgressIndicator(
        progress = progress.floatValue,
        modifier = Modifier.padding(16.dp),
        //进度条颜色
        color = Color.Red,
        //背景颜色
        trackColor = Color.Gray,
        //进度条样式
        strokeCap = StrokeCap.Round
    )
}

Slider
@Composable
fun SliderView() {
    val position = remember { mutableFloatStateOf(0.3f) }
    Slider(
        value = position.floatValue,
        onValueChange = { newValue -> position.floatValue = newValue },
        valueRange = 0f..100f,
        modifier = Modifier.padding(16.dp),
        colors = SliderDefaults.colors(
            //滑块颜色
            thumbColor = Color.Red,
            //滑轨颜色
            activeTrackColor = Color.Green,
            //滑轨背景颜色
            inactiveTrackColor = Color.Gray
        )
    )
}

ViewGroup

接下来给大家介绍一下常用布局的简单使用,也是以图文形式进行示例。

名称描述
Scaffold一个基础布局,通常包含顶部栏、底部栏和一个内容区域
Column垂直布局
Row水平布局
Surface一个通用的布局容器,可以设置背景色、形状等
Card卡片布局
LazyColumn懒加载的垂直滚动列表
LazyRow懒加载的水平滚动列表
Scaffold
class MainActivity : ComponentActivity() {
    @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                Scaffold(
                    topBar = {
                        Text("Jetpack Compose", modifier = Modifier.padding(16.dp, 0.dp, 0.dp, 0.dp))
                    },
                    content = {
                        Surface(
                            modifier = Modifier.fillMaxSize(),
                            color = MaterialTheme.colorScheme.background
                        ) {
                            GreetingPreview()
                        }
                    }
                )
            }
        }
    }
}

Column
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyApplicationTheme {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp),
            verticalArrangement = Arrangement.Center
        ) {
            ButtonView()
            ButtonView()
            ButtonView()
            ButtonView()
        }
    }
}

Row
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyApplicationTheme {
        Row(
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp),
            horizontalArrangement = Arrangement.Start
        ) {
            ShowImage()
            ShowImage()
            ShowImage()
        }
    }
}

Surface
@Composable
fun SurfaceLayout() {
    Surface(
        color = Color.Blue,
        modifier = Modifier
            .padding(8.dp)
            .size(300.dp, 200.dp)
    ) {
        Text("This is Surface Layout", color = Color.White)
    }
}

Card
@Composable
fun CardLayout() {
    Card(
        modifier = Modifier
            .padding(8.dp)
            .size(300.dp, 200.dp),
        //设置圆角
        shape = RoundedCornerShape(20.dp),
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Text(
                "This is Card Layout",
                textAlign = TextAlign.Center,
                color = Color.Black,
                fontSize = 20.sp
            )
        }
    }
}

LazyColumn
@Composable
fun LazyColumnLayout() {
    val context = LocalContext.current
    val items = mutableListOf<String>()
    for (i in 0..50) {
        items += "Item data $i"
    }

    //懒加载的列表,只有当item出现在屏幕上时才会加载
    LazyColumn {
        items(items) { item ->
            Text(text = item, modifier = Modifier
                .padding(16.dp)
                .clickable {
                    Toast
                        .makeText(context, item, Toast.LENGTH_SHORT)
                        .show()
                })
        }
    }
}

设计

主题和样式
//黑夜主题颜色
private val DarkColorScheme = darkColorScheme(
   primary = Purple80,
   secondary = PurpleGrey80,
   tertiary = Pink80
)

//白天主题颜色
private val LightColorScheme = lightColorScheme(
   primary = Purple40,
   secondary = PurpleGrey40,
   tertiary = Pink40
)

@Composable
fun MyApplicationTheme(
   //主题模式
   darkTheme: Boolean = isSystemInDarkTheme(),
   //是否动态颜色
   dynamicColor: Boolean = true,
   //布局
   content: @Composable () -> Unit
) {
   val colorScheme = when {
       dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
           val context = LocalContext.current
           if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
       }

       darkTheme -> DarkColorScheme
       else -> LightColorScheme
   }

   MaterialTheme(
       colorScheme = colorScheme,
       typography = Typography,
       content = content
   )
}

val Typography = Typography(
        bodyLarge = TextStyle(
                //字体样式
                fontFamily = FontFamily.Default,
                fontWeight = FontWeight.Normal,
                fontSize = 16.sp,
                lineHeight = 24.sp,
                letterSpacing = 0.5.sp
        )
        /* Other default text styles to override
    titleLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 22.sp,
        lineHeight = 28.sp,
        letterSpacing = 0.sp
    ),
    labelSmall = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Medium,
        fontSize = 11.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.5.sp
    )
    */
)

动画
开启 animateFloatAsState 动画
@Composable
fun StartFloatAnimation() {
    var started by remember { mutableStateOf(false) }
    // 使用 animateFloatAsState 创建浮点数动画
    val size by animateFloatAsState(
        if (started) {
            200f
        } else {
            100f
        },
        visibilityThreshold = 0.1f,
        // 使用 keyframes 定义动画的持续时间
        animationSpec = keyframes {
            durationMillis = 1000
        }, label = ""
    )
    Box(
        modifier = Modifier
            .size(size.dp)
            .background(Color.Blue)
            .clickable { started = !started } // 点击时切换大小
    )
}

开启 animateTo 动画
@Composable
fun StartAnimationToColor() {
    val color = remember { Animatable(Color.Red) }
    // //创建一个协程
    val scope = rememberCoroutineScope()
    Box(modifier = Modifier
        .size(240.dp)
        .background(color.value)
        .clickable {
            // 开启协程
            scope.launch {
                // 改变动画到目标颜色
                color.animateTo(
                    targetValue = Color.Blue,
                    animationSpec = tween(durationMillis = 5000, easing = LinearOutSlowInEasing)
                )
            }
        }
    )
}

总结

以上就是 Compose 的简单使用,帮助大家对 Compose 有个初步的认识和了解,如果想要了解更多,建议直接访问官网。从个人角度出发,对于 Android 开发者来讲 Compose 还是比较容易上手,特别是有 Flutter 开发经验会更比较容易接受和掌握。所以,对于感兴趣的同学赶紧学起来吧!

总的来说,Compose 是一个强大、灵活、现代的 Android UI 工具包,可以帮助大家更高效地进行 UI 开发。
如果你看到了这里,觉得文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料


在这里插入图片描述
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )

  • 28
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值