Jetpack Compose初识

2021-03-29  本文已影响0人  塞上牧羊空许约

何为Compose

2019 年中,Google 在 I/O 大会上公布的用于Android构建原生界面的全新 UI 框架。也就是说它的渲染机制、布局机制、触摸算法以及 UI 的具体写法,全都是新的。啊,这难道要把我们Android开发者赖以生存的技能---画xml,给点灭啦?

为啥要学

作为Google新推出的一套全新ui框架,Compose有别于传统的xml+java(kotlin)的“命令式ui”写法,它是一种“声明式ui”,iOS 的 SwiftUI 以及跨平台的 Flutter 也都是声明式的,可见声明式 UI 已经是一种趋势了(扶我起来,我还能学.jpg)。那它有那些好处呢?

Compose vs Xml+Java/Kotlin

前者只要声明界面是什么样子,不用手动去更新,因为界面会自动更新,而且去掉了xml,只需使用Kotlin即可。而后者数据发生了改变,我们得手动用 Java 代码或者 Kotlin 代码去把新数据更新到界面。给出详细的步骤,去命令界面进行更新。

xml

 setContentView(R.layout.activity_compare)
 findViewById<TextView>(R.id.tv_greeting).text = "Hello Android"

compose

    @Preview
    @Composable
    fun FirstPreview() {
        var name by remember { mutableStateOf("Hello Compose") }
        Story(name)
        name = "Hello Android"
    }

    @Composable
    fun Story(name: String) {
        Text(name, textAlign = TextAlign.Center)
    }

状态管理

状态

app中的状态(State)指的是一个可以随着时间变化的值。我们的应用就是在向用户展示状态。Compose可以让我们明确状态存储的位置和方式。

组合和重组

组合(composition)就是由一个个Composable调用形成的树形结构,运行这些Composable便可展示出我们的ui,在初识组合期间,Compose会对这些构建ui的Composable函数进行跟踪,当app的状态发生改变时,Compose会进行一次重组(recomposition)来更新ui。
组合只能由初始组合产生,并且只能由重组更新。修改的唯一方法就是重组。
Talk is cheap, show me the code

    // this stateful composable is only responsible for holding internal state
    // and defers the UI to the stateless composable
    @Composable
    fun ExpandingCard(title: String, body: String) {
        var expanded by remember { mutableStateOf(false) }
        ExpandingCard(
            title = title,
            body = body,
            expanded = expanded,
            onExpand = { expanded = true },
            onCollapse = { expanded = false }
        )
    }
    
    // this stateless composable is responsible for describing the UI based on the state
    // passed to it and firing events in response to the buttons being pressed
    @Composable
    fun ExpandingCard(
        title: String,
        body: String,
        expanded: Boolean,
        onExpand: () -> Unit,
        onCollapse: () -> Unit
    ) {
        Card {
            Column(
                Modifier
                    .width(280.dp)
                    .animateContentSize() // automatically animate size when it changes
                    .padding(top = 16.dp, start = 16.dp, end = 16.dp)
            ) {
                Text(title)
                if (expanded) {
                    Spacer(Modifier.height(8.dp))
                    Text(body)
                    IconButton(onClick = onCollapse, Modifier.fillMaxWidth()) {
                        Icon(Icons.Default.KeyboardArrowUp, "Expand Less")
                    }
                } else {
                    IconButton(onClick = onExpand, Modifier.fillMaxWidth()) {
                        Icon(Icons.Default.KeyboardArrowDown, contentDescription = "Expand more")
                    }
                }
            }
        }
    }

其中mutableState会返回一个MutableState,是一个可被观察的类型,它的值一旦发生变化,那么任何使用它的值的Composable函数将会发生重组,然后更新组合。remember的作用就是将状态的值存储在内存中,给Composable函数赋予”记忆“的功能,不会在每次重组中将上一次的值丢失。然而当发生切换屏幕方向,切换语言这些configuration changes时,remember便无能为力了,这时候rememberSaveable就可以派上用场啦。rememberSaveable可以自动将任何可以放在Bundle的值存储下来。

Composable的生命周期

lifecycle-composition.png

互操作性

Xml里使用Compose

通过使用ComposeView然后调用setContent方法即可

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".compare.ComposeInXmlActivity">
    <TextView
        android:id="@+id/hello_world"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Hello Android!" />

    <androidx.compose.ui.platform.ComposeView
        android:id="@+id/compose_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center" />
</LinearLayout>
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_compose_in_xml)

        findViewById<ComposeView>(R.id.compose_view).setContent {
            Text("Hello Compse")
        }
    }

Compose里使用Android View

通过使用AndoridView可以引入一个view

    @Composable
    private fun PlantDescription(description: String) {
        // Remembers the HTML formatted description. Re-executes on a new description
        val htmlDescription = remember(description) {
            HtmlCompat.fromHtml(description, HtmlCompat.FROM_HTML_MODE_COMPACT)
        }

        // Displays the TextView on the screen and updates with the HTML description when inflated
        // Updates to htmlDescription will make AndroidView recompose and update the text
        AndroidView(
            factory = { context ->
                TextView(context).apply {
                    movementMethod = LinkMovementMethod.getInstance()
                }
            },
            update = {
                it.text = htmlDescription
            }
        )
    }

    @Preview
    @Composable
    private fun PlantDescriptionPreview() {
        MaterialTheme {
            PlantDescription("HTML<br><br>description")
        }
    }

学习资源

https://developer.android.com/jetpack/compose/state?hl=zh-cn

上一篇下一篇

猜你喜欢

热点阅读