在Google IO 2019上看到有关Android Jetpack Compose的话题后,我想立即尝试一下。 而且,其中实现的方法使我非常想起Flutter,这让我很感兴趣 。

Compose库本身处于pre-alpha阶段,因此没有多少可用的文档和文章。 接下来,我将依靠我设法找到的几种资源以及开源库 。
这些资源是:
什么是Android Jetpack Compose?
以前,整个Android UI都基于View类。 自Android早期以来就是这种情况。 在这方面,已经积累了许多遗留和体系结构缺陷,可以改善这些缺陷。 但是要做到这一点非常困难,而又不破坏所有基于其编写的代码。
在过去的几年中,客户端应用程序世界中出现了许多新概念(包括Frontend趋势),因此Google团队采取了激进的道路,并从头重写了Android中的整个UI级别。 于是出现了Android Jetpack Compose库,其中包括React,Litho,Vue,Flutter等许多概念性技巧。
让我们看一下现有UI的一些功能,并将其与Compose进行比较。
1.独立于Android版本
现有的UI与平台密切相关。 当Material Design的第一个组件出现时,它们仅适用于Android 5(API21)及更高版本。 要在较旧版本的系统上工作,必须使用支持库。
Compose是Jetpack的一部分,它使它独立于系统版本,甚至可以在较旧的Android版本中使用(至少与API21配合使用)。
2.整个Kotlin API
以前,您必须处理不同的文件才能创建UI。 我们以xml描述了标记,然后使用Java / Kotlin代码使其工作。 然后,我们返回到其他xml文件以设置主题,动画,导航等。甚至尝试用xml编写代码(数据绑定)。
使用Kotlin允许您直接用代码而不是xml编写声明式的UI。
3. Composable = Composite:使用合成代替继承
创建自定义UI元素可能很麻烦。 我们需要从View或其后代继承,并照顾好许多重要的属性,然后才能正确启动它。 例如,TextView类包含大约3万行Java代码。 这是由于这样的事实,它内部包含许多不必要的逻辑,这些逻辑由后代元素继承。
另一方面,Compose出现了,用组合代替了继承。
Padding
最适合说明其含义:
在现有的UI中,为了呈现缩进30dp
的TextView
:
我们需要编写以下代码:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" android:padding="30dp" <------------------------ NOTE THIS android:text="Drag or tap on the seek bar" />
这意味着在TextView.java或其超类内部的某个位置,存在知道如何计算和绘制缩进量的逻辑。
让我们看看如何在Compose中执行相同的操作:
变化
TextView
变成了Text()
。 android:padding
属性已变成Padding
Text
的Padding
。
好处
因此, Text
仅负责呈现文本本身。 他不知道如何计算缩进量。 另一方面,填充仅负责填充,仅此而已。 它可以在任何其他元素周围使用。
4.单向数据流
如果我们谈论例如在现有UI系统中控制CheckBox
的状态,则单向数据流是一个重要的概念。 当用户点击CheckBox
,其状态变为checked = true
:该类更新View状态并从监视状态变化的代码中调用回调。
然后,在代码本身中,例如在ViewModel
,您需要更新相应的state
变量。 现在,您有两个按下状态的副本,这可能会造成问题。 例如,更改ViewModel
内部state
变量的值将导致CheckBox
更新,这可能以无休止的循环结束。 为了避免这种情况,我们将不得不提出某种拐杖。
由于基于单点原则,因此使用Compose将有助于解决这些问题。 状态更改将在框架内处理:我们只向内提供数据模型。 此外,Compose中的组件现在不会自行更改其状态。 相反,它仅调用回调,而现在是更改UI的应用程序任务。
5.改善调试
由于整个UI现在都是用Kotlin编写的,因此您现在可以调试UI。 我自己没有尝试过此操作,但是在播客中,他们说调试器和断点在Compose中有效。
足够的单词,显示代码
我知道,我想快速查看代码中的UI外观(扰流板:如果您尝试在Flutter上编写,则非常类似于Flutter)。
我们将从创建一些简单的View
,然后比较它们在现有UI和Compose中的外观。
1. FrameLayout
与Wrap + Padding + Background
我们重用上面的示例,并尝试使此TextView
缩进为30dp
并带有青绿色背景:
现有的用户界面:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" <-------------- NOTE THIS android:padding="30dp" <------------------------ AND THIS android:text="Drag or tap on the seek bar" />
现在看一下在Compose中执行相同操作的代码:
@Composable fun MyText() { Wrap { Padding(30.dp) { DrawRectangle(color = Color.Cyan) Text("Drag or tap on the seek bar") } } }
这里有一些新东西。 由于Text
只知道渲染文本,因此不关心填充和背景。 因此,要添加它们,我们需要使用三个单独的函数:
DrawRectangle
背景Padding
缩进Wrap
是覆盖诸如FrameLayout
参数的函数。
很简单 但这与我们都习惯的现有UI系统略有不同。
2.垂直LinearLayout
与Column
现在,让我们尝试做一些等效于我们旧的LinearLayout
。
要将两个元素放在另一个元素的下面,如下图所示,我们可以使用Column
:
该代码将如下所示:
@Composable fun FormDemo() { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") Button(text = "Next") } }
嵌套在Column
元素中的元素将垂直位于另一个元素的下方。
2a。 压痕
您可能已经注意到文本和按钮离边缘太近了。 因此,添加Padding
。
@Composable fun FormDemo() { Padding(10.dp) {
看起来更好:
2b。 间隔
我们还可以在Text
和Button
之间添加一些缩进:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp)
现在我们的屏幕是什么样的:
2c。 水平LinearLayout
与Row
将第二个按钮放在第一个按钮旁边:
代码如下:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) Row {
Row
两个按钮将为水平。 WidthSpacer
会增加它们之间的距离。
2d。 Gravity
与Alignment
就像在当前用户界面中的gravity
一样,将元素对准中心。 为了显示差异,我将旧行注释掉并用新行替换:
@Composable fun FormDemo() { Padding(10.dp) {
我们将成功:
使用crossAxisAlignment = CrossAxisAlignment.Center
嵌套元素将水平居中。 我们还应该将Row
参数设置为mainAxisSize = FlexSize.Min
,其行为与layout_width = wrap_content
相似,因此由于默认的mainAxisSize = FlexSize.Max
,它不会在屏幕上mainAxisSize = FlexSize.Max
,其行为类似于layout_width = match_parent
。
2d。 备注
从上面的示例中我们可以看到,所有元素都是由单独的函数构成的: padding
是单独的函数, spacer
是单独的函数,而不是Text
, Button
或Column
内部的属性。
诸如RecyclerView
或ConstraintLayout
类的更复杂的元素正在开发中:因此,我无法在演示源中找到有关它们的示例。
3.样式和主题
您可能已经注意到,默认情况下,上面的按钮是紫色的。 这是因为它们使用默认样式。 让我们看看样式如何在Compose中工作。
在上面的示例中, FormDemo
带有@Composable
注释。 现在,我将展示如何在Activity
使用此元素:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{ MaterialTheme { FormDemo() } } } }
代替setContentView()
函数,我们使用setContent()
,它是Compose.kt
库中的扩展函数。
CraneWrapper
包含Compose树,并提供对Context
, Density
, FocusManager
和TextInputService
。
MaterialTheme
允许您自定义元素的主题。
例如,可以将主题的原色更改为棕色,如下所示:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{
现在,我们的屏幕将如下所示:
可以更改的其他颜色和字体: MaterialTheme.kt#57
Rally Activity提供了一个很好的示例,可以如何自定义主题: RallyTheme.kt的源代码
看什么/读什么
如果需要更多,可以根据此处的说明组装示例项目。
正如Windows用户所写的那样,现在没有启动Compose的正式方法,但是kotlinlang Slack提供了一个非官方的指南 。
可以在#compose
kotlinlang Slack频道中向开发人员询问有关Compose的问题。
在评论中保留其他链接-最有用的链接将在此处添加。
结论
该库的开发如火如荼,因此此处显示的任何接口均可能发生变化。 您还可以在源代码中学习很多东西,例如@Model
和单向数据流(单向数据流)。 也许这是以后文章的主题。