1、Jetpack Compose入门 --- 初识Jetpack Compose

235 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情

一、为什么要学 Jetpack Compose?

解决这个问题之前,我给自己找了几个理由:

  1. Compose使用声明式UI构建整个页面,像跨平台的Flutter、IOS的SwiftUI、鸿蒙的ArkUI,这些都是声明式UI,可见声明式UI已经是移动开发未来的大趋势了。
  2. Compose抛弃了传统的界面绘制机制,引入了固有特性测量(Intrinsic Measurement),这使得界面在绘制时不会多次测量同一个控件,因此界面绘制速度将会大大加快,在一些复杂的页面或控件中效果尤其明显。
  3. Compose整个系统都是严格按照 Material Design 进行设计的,利用 MaterialTheme 可以让我们更加方法地进行主题管理,甚至是主题切换。
  4. 基于Compose的UI界面,其数据信任单一来源,使得UI的展示与真实数据能够更好地做到统一。
  5. Android Studio 4.0 以上的编辑器,有着强大的工具,并且Compose使用的是 Kotlin Api,使得代码量被大幅度地减少,开发速度将会变得更快。
  6. Compose作为Jetpack全家桶的一员,为什么不学呢?

9105037A.jpg

二、从Google官网入手

1、先来看看Compose首页上的宣传图

google compose效果宣传图 image.png 短短几行代码,就实现了这样的界面效果,看着就让人心动!

2、再来看看官方提供的代码

google先后提供了如下两种写法: 第一种:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        } 
    }
}

第二种:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("world") 
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
} 

image.png

运行起来的效果就是这样一个居于页面左上角的文本,此处有几点需要注意:

  1. 我们的Activity需要继承自ComponentActivity,注意是androidx.activity.ComponentActivity,不是androidx.core.app.ComponentActivity,前者并不是一个Activity这么简单,有时间的话可以去看一下源码。
  2. setContent{}函数里面,定义的就是我们的布局,类似于传统写法中的setContentView(R.layout.main)
  3. 第二种写法中的MessageCard函数带有@Compose注解,表示这是一个可组合函数(也就是我们的布局所需要的组件),并且所有的可组合函数都必须带有此注解。

三、自己动手开干

image.png

我这里选择的是 Android Studio Bumblebee。在这个版本的AS下,我们可以做到:

  • New Project 的时候,可以直接创建一个基于Compose的工程项目。
  • 支持对Compose界面的实时预览,并且可以通过Start Interactive Mode,在预览界面上进行一些简单的交互测试。

创建功能

image.png

build.gradle配置

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 31

    defaultConfig {
        ...
        minSdk 21
    }
    
    ...
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
    
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion compose_version
    }
    
    ...
}

dependencies {
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.activity:activity-compose:1.3.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
}

这里有几个需要注意的问题:

  1. 要使用Compose,必须得支持Kotlin。并且,如果你使用的compose版本是1.0.5版本的话,Kotlin的版本需要使用1.5.31或更高;如果你使用compose的1.1.1版本,则需要Kotlin版本1.6.10或更高。PS:我这里使用的是compose1.0.5 + kotlin1.5.31
  2. minSdk最小需要支持到Api21
  3. 需要将Java和Kotlin的编辑器目标设置为Java8
  4. 需要打开compose的enable开关

接下来,在dependencies中,我们可以看到几个关键的库:

implementation "androidx.compose.ui:ui:$compose_version"
// 主题
implementation "androidx.compose.material:material:$compose_version"
implementation 'androidx.activity:activity-compose:1.3.1'
// 工具支持
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"

接下来,利用Compose提供的组件实现一个简单的页面

GIF 2022-1-30 23-15-09.gif

代码如下:

@Composable
fun BasicWidget() {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        //文字
        Text(text = "这是一个文字",
            modifier = Modifier.clickable { showShort("这是一个Text") })
        //图片
        Image(painter = painterResource(id = R.drawable.panda),
            contentDescription = null,
            modifier = Modifier.clickable { showShort("这是一个Image") })
        //图标
        Icon(painter = painterResource(id = R.drawable.panda),
            contentDescription = null,
            modifier = Modifier.clickable { showShort("这是一个Icon") })
        //按钮
        Button(onClick = { showShort("这是一个Button") }) {}
        //开关
        val switchState = remember { mutableStateOf(true) }
        Switch(checked = switchState.value, onCheckedChange = {
            switchState.value = it
            showShort("开关:$it")
        })
        //单选框
        val selectedState = remember { mutableStateOf(false) }
        RadioButton(selected = selectedState.value, onClick = {
            selectedState.value = selectedState.value.not()
            showShort("单选框:${selectedState.value}")
        })
        //复选框
        val checkState = remember { mutableStateOf(false) }
        Checkbox(checked = checkState.value, onCheckedChange = {
            checkState.value = it
            showShort("复选框:${it}")
        })
    }
}