代码编织梦想

简介

Jetpack Compose 是用于构建native UI的新方式,写法跟Flutter非常相似,对Flutter有了解的同学可以很快上手。
官网:https://developer.android.com/jetpack/compose
官方demo :https://github.com/android/compose-samples
官方的介绍: https://developer.android.com/jetpack/compose/setup

环境及版本

最低支持Android API 21,即5.0版本,必须使用kotlin语言,最低使用Android Studio 4.0 版本。
Jetpack Compose 目前处于实验阶段,现在是0.1-dev2,到1.0正式版估计还要一年时间。
后续版本可能会加入更多kotlin的特性,丰富动画等其他性能问题。

关于如何在现有项目中使用:
https://developer.android.com/jetpack/compose/setup#add-compose

怎么使用?

在AS 4.0中直接新建一个空的Compose项目,会有一个示例代码:
在这里插入图片描述
在函数前加@Compose注解,就可以返回一个类似Flutter中的Widget的UI
@Compose注解的函数可以相互调用,这些函数会被插件编译处理,所以如果一个函数不是生成UI的,那么不要用此注解。
@Preview注解,可以在右边实时预览,改动函数后,刷新一个预览即可,添加该注解的外层函数不能有参数,但是里面可以嵌套一个带参数的函数来预览。可以在@Preview后面添加一个名字,如:@Preview("Text preview")

关于Column 和Row 的概念跟Flutter中一样,包括主轴和副轴的概念大小如mainAxisSize和对齐方式如crossAxisAlignment,一段代码示例:

@Composable
fun MyScreenContent(
    names: List<String> = listOf("Android", "there"),
    counterState: CounterState = CounterState()
) {
    Column(crossAxisAlignment = CrossAxisAlignment.Center
      crossAxisSize = LayoutSize.Expand,
        mainAxisSize = LayoutSize.Expand) {
        for (name in names) {
            Greeting(name = name)
            Divider(color = Color.Black)
        }
        Divider(color = Color.Transparent, height = 32.dp)
        Counter(counterState)
    }
}

@Preview("MyScreen preview")
@Composable
fun DefaultPreview() {
    MyApp {
        MyScreenContent()
    }
}

可以使用HeightSpacer(24.dp)或者WeightSpacer(24.dp)来直接添加一个宽高间隔

按照官方的建议,我们可以把UI拆分成多个小的Compose函数,每个函数其实最终会被插件编译生成一个View,然后可以复用这些Compose函数,

@Composable
fun MyScreenContent(
    names: List<String> = listOf("Android", "there"),
    counterState: CounterState = CounterState()
) {
    Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
        Column(modifier = Flexible(1f), crossAxisAlignment = CrossAxisAlignment.Center) {
            for (name in names) {
                Greeting(name = name)
                Divider(color = Color.Black)
            }
        }
        Counter(counterState)
    }
}

在Column中,可以对参数modifier设置ExpandedHeight,类似于设置高度match_parent的意思,宽度同理。

关于如何使用Theme和自定义Theme

MaterialTheme中有很多颜色和字体样式,在外层包裹上MaterialTheme后,可以在内部的Compose函数中使用主题数据,如:style = +themeTextStyle { h1 }

@Composable
fun Greeting(name: String) {
    Text (
        text = "Hello $name!",
        modifier = Spacing(24.dp),
        style = +themeTextStyle { h1 }
        color = +themeColor { surface }
    )
}

通过使用copy函数可以在现有的一个主题上修改某一个属性值,如:

textStyle = (+themeTextStyle { body1 }).copy(color = Color.Yellow)

自定义Theme

import androidx.compose.Composable

@Composable
fun CustomTheme(children: @Composable() () -> Unit) {
    // TODO 
}
import androidx.compose.Composable
import androidx.ui.core.CurrentTextStyleProvider
import androidx.ui.graphics.Color
import androidx.ui.material.MaterialColors
import androidx.ui.material.MaterialTheme
import androidx.ui.text.TextStyle

val green = Color(0xFF1EB980.toInt())
val grey = Color(0xFF26282F.toInt())
private val themeColors = MaterialColors(
    primary = green,
    surface = grey,
    onSurface = Color.White
)

@Composable
fun CustomTheme(children: @Composable() () -> Unit) {
    MaterialTheme(colors = themeColors) {
        val textStyle = TextStyle(color = Color.Red)
        CurrentTextStyleProvider(value = textStyle) {
            children()
        }
    }
}

Effects和memo

memo的作用:

1. 在recompositions(即该UI组件内部的Model数据变化时,该UI组件就会重新构建)的时候保存状态值,如下代码:

@Composable
fun MyScreenContent(
    names: List<String> = listOf("Android", "there"),
    counterState: CounterState = CounterState()
) { ... }

上面的代码有一个问题,再重新构建的时候,原来的counterState数值就会丢失,每次都是一个新的counterState对象。
按照下面使用memo修改后,就可以解决问题:

@Composable
fun MyScreenContent(
    names: List<String> = listOf("Android", "there"),
    counterState: CounterState = +memo { CounterState() }
) { ... }

2. 在重组时,记住内部的一些计算结果,防止多次重复计算

如果在合成的中间需要进行计算,而又不想在每次重新组合函数时都进行计算,则可以记住该计算,即使重新组合了Composable函数,该计算也不会再次执行。

@Composable
fun Greeting(name: String) {

    val formattedName = +memo { name.substringBefore(" ").toUpperCase() }

    Text (
        text = "Hello $formattedName!",
        modifier = Spacing(24.dp),
        style = +themeTextStyle { h3 }
    )
}

@Preview
@Composable
fun DefaultPreview() {
    MaterialTheme {
        Greeting("Android 10")
    }
}

比如这里的formattedName计算过程,在使用memo后,就不会重复计算,但是这样写有个bug,如果第二次调用时传入来了另外一个参数,那么由于memo复用原来的结果,就会导致bug,所以,对于需要修改的参数,可以以如下的方式来使用memo:

@Composable
fun Greeting(name: String) {

    val formattedName = +memo(name) { name.substringBefore(" ").toUpperCase() }

    Text (
        text = "Hello $formattedName!",
        modifier = Spacing(24.dp),
        style = +themeTextStyle { h3 }
    )
}

@Model注解

model注解标记一个数据类之后,在Compose函数中可以直接监听到数据变化,自动更新显示,
如:
定义:

@Model 
class CounterState(var count: Int = 0)

使用:

@Composable 
fun Counter(state: CounterState) {
    Button(
        text = "I've been clicked ${state.count} times",
        onClick = {
            state.count++
        }
    )
}

状态提升、 数据流向下传递、事件流向上传递

@Model
class FormState(var optionChecked: Boolean)

@Composable
fun Form(formState: FormState) {
    Checkbox(
        checked = formState.optionChecked,
        onCheckedChange = { newState -> formState.optionChecked = newState })
}

在上面代码中,Checkbox的选中状态,在Checkbox和Form中都不保存,而改为由外部传入,原因是此时外部可能需要使用当前的状态值,那么由外部来创建并传递该参数到Compose函数中,这使得外部调用者提升了状态

⚠️注意:在可组合函数中,应该公开可能对调用函数有用的状态,因为这是可以使用或控制的唯一方法,称为状态提升。

状态提升的概念跟Flutter一样,后续应该也会像Flutter中的Provider、BLOC、或者Redux一样,推出相关的状态管理库,因为Compose + Model注解的方式,就是一种MVVM的思想,需要一种方便的数据状态管理的三方库来做这个事情。

关于数据流向: 父Composable函数可以控制其子数据。 子Compose UI不应从全局变量或全局数据存储中读取。Composable函数应仅接收所需信息,因此它们应尽可能简单,而不是调用父Composable函数可以提供的所有内容。

@Composable
fun MultipleGreetings(user: User = +memo { User("name", "surname") }) {
    Column {
        Greeting("${user.firstName} ${user.lastName}")
        Greeting("Android 10")
        Button(text = "Change name", onClick = {
            user.firstName = "Changed"
            user.lastName = "New surname"
        })
    }
}

@Composable
fun Greeting(name: String) {

    val formattedName = +memo(name) { name.substringBefore(" ").toUpperCase() }

    Text (
        text = "Hello $formattedName!",
        modifier = Spacing(24.dp),
        style = +themeTextStyle { h3 }
    )
}

比如上面代码中,Greeting从调用方Compose函数(MultipleGreetings)获取数据,作为参数传入,且Greeting只接收一个String,并不是整个User对象。

事件向上传递

事件通过lambda回调而不断往上。 当子Composable函数收到事件时,更改应传播回至关心该信息的Composable。

在我们的示例中,我们可以通过将Greeting的内容包装在以onClick侦听器为参数的Clickable函数(可在库中使用)中来使其可点击。 但是,Greeting是一个可重用的功能,它本身并不知道如何处理用户交互。 应该使用lambda将该信息从层次结构的底部(Greeting中的Clickable composable)传播到顶部的Composable函数,这些函数知道如何处理该信息,如以下示例所示:

@Composable
fun MultipleGreetings(user: User = +memo { User("name", "surname") }) {

    val onClick = {
        user.firstName = "Changed"
    }

    Column {
        Greeting("${user.firstName} ${user.lastName}", onClick)
        Greeting("Android 10", onClick)
        Button(text = "Change name", onClick = onClick)
    }
}

@Composable
fun Greeting(name: String, onClick: () -> Unit) {

    val formattedName = +memo(name) { name.substringBefore(" ").toUpperCase() }

    Clickable(onClick = onClick) {
        Text (
            text = "Hello $formattedName!",
            modifier = Spacing(24.dp),
            style = +themeTextStyle { h3 }
        )
    }
}

Greeting通过调用父级作为参数传递的lambda告诉MultipleGreetings它被单击了。 如果您运行该应用程序,则可以看到在任何问候语文本上进行点击都会传播更改,并且顶部的Greeting实例将重新组合。

在这里插入图片描述
Data flow in Compose apps. Data flows down with parameters, events flow up with lambdas.
Data flow in Compose apps. Data flows down with parameters, events flow up with lambdas.


Compose和现有的View互操作

Compose写的函数可以用在xml中,Android现有的View也可以用Compose的方式来写,如:
在这里插入图片描述
在这里插入图片描述
总结: Compose借鉴了Flutter和Swift UI的编写方式,代码简洁,可以实时预览效果,截止到2019年11月19日,目前版本才为0.1,预计正式发布1.0后,会有更多功能更新,日常的一个小demo可以先使用Compose熟悉起来。

参考:
https://codelabs.developers.google.com/codelabs/jetpack-compose-basics/#0

牛逼!Android Jetpack Compose UI组件库最新进展,写法完全类似Flutter

Android Studio 4.0 最新进展,这几个新功能可太牛逼了!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/unicorn97/article/details/103137105

Jetpack Compose 自定义绘制-爱代码爱编程

概述 Jetpack Compose 作为一款 UI 框架,自定义绘制部分是必不可少的。通过官方所提供的基础 API, 允许开发者实现各种场景下的绘制定制需求。如果你对 Android 原生 Canvas 已经了如指掌的话,那么迁移至 Jetpack Compose 基本没有任何成本。即使你不曾了解 Android 原生 Canvas 也不要担心,阅读这

React-redux之compose-爱代码爱编程

compose 源码 先来看一下compose的源码官网源码 /** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature f

Don't break the chain: use RxJava's compose() operator-爱代码爱编程

https://blog.danlew.net/2015/03/02/dont-break-the-chain/ One nice aspect of RxJava is that you can see how data is transformed through a series of operators: Observable.from(som

redux剖析-爱代码爱编程

redux剖析 reduxRedux流程图combineReducerscreateStoreapplyMiddlewarecomposereact-reduxProviderconnect参考文献 redux redux是flux的进化版,flux流程图(图片来源:http://caibaojian.com/react/flux.html)

jetpack使用、viewModel、databinding开发-爱代码爱编程

为了代码的简洁还有数据界面之间耦合的问题,谷歌推荐我们使用jetpack进行开发,今天学习了一下,现在把它给记录下来 我们做一个简单的计数器来方便大家更进一步的了解并使用 点击按钮+1,好的,现在开始贴代码,一步一步来。 1,首先就是布局了,一个简单的约束布局,里面有一个textView和一个Button。 2,接下来这一步挺重要的,我们首先建

Android Jetpack DataBinding入门填坑(三)-爱代码爱编程

Jetpack系列 Android Jetpack WorkManager初级认识 Android Jetpack ViewModel由浅入深 附上官网地址https://developer.android.com/topic/libraries/data-binding/expressions 一、DataBinding的定义及作用 是一个支持

Android Jetpack架构组件之LiveData-爱代码爱编程

有时候,靠单纯的判断并不能确定成功的几率。与其在等待中浪费青春,不如在追求中燃烧生命。——《狼道》 目录 前言 一、简介 ​二、基本使用 三、源码分析 四、内容推荐 五、项目参考 前言 ——这篇记录的是一个常用的Jetpack架构组件之一的LiveData。通俗讲它有两个显著作用:1.通过观察者模式当数据发生变化的时候通知U

Flutter学习资源-爱代码爱编程

系统学习资源 Flutter社区中文资源:https://flutter.cnFlutter中文网:https://flutterchina.club/Dart编程语言:http://www.dartdoc.cn/Flutter实战:https://book.flutterchina.club/Flutter自定义Widget:http://flutte

TX2刷机 ubuntu18.04+ jetpack4.2+cuda10.0+ssd-caffe踩坑集锦-爱代码爱编程

故事起因:因为误信了一篇博客,删掉了bash文件,导致系统无限重启,于是我开始了漫长的探索之路。 **ps:系统文件最好别删,谁删谁知道。**刚开始还幻想直接将bash文件搞进去,后来发现网上的教程是用u盘启动,应该不适用于tx2,遂放弃。直接刷机。 比较重要的一点是:tx2用的arm结构,是aarch-linux,不是x86_64-linux,也不是i3

Android Jetpack架构组件 — Room入坑详解-爱代码爱编程

本文首发于微信公众号「Android开发之旅」,欢迎关注 ,获取更多技术干货 Jetpack版Wan-Android项目地址:Android Jetpack架构开发组件化应用实战 欢迎star Flutter版Wan-Android项目地址:Flutter版Wan-Android 欢迎star Room是Jetpack组件库一员,属于ORM