Android Jetpack构成第一印象

在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中,为了呈现缩进30dpTextView


图片

我们需要编写以下代码:


 <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中执行相同的操作:


 // note: the cyan background color is omitted for now to keep it simple Padding(30.dp) { Text("Drag or tap on the seek bar") } 

变化
TextView变成了Text()android:padding属性已变成Padding TextPadding


好处
因此, 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. FrameLayoutWrap + Padding + Background


我们重用上面的示例,并尝试使此TextView缩进为30dp并带有青绿色背景:


缩进为30dp和引入背景的“ TextView”

现有的用户界面:


 <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.垂直LinearLayoutColumn


现在,让我们尝试做一些等效于我们旧的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) { //   Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") Button(text = "Next") } } } 

看起来更好:


两个元素缩进一个在另一个之下

2b。 间隔


我们还可以在TextButton之间添加一些缩进:


 @Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) //    Button(text = "Next") } } } 

现在我们的屏幕是什么样的:


缩进和倾斜的两个元素,一个在另一个下面

2c。 水平LinearLayoutRow


将第二个按钮放在第一个按钮旁边:


添加了第二个按钮

代码如下:


 @Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) Row { //   Button(text = "Back") //   WidthSpacer(10.dp) //    Button(text = "Next") } } } } 

Row两个按钮将为水平。 WidthSpacer会增加它们之间的距离。


2d。 GravityAlignment


就像在当前用户界面中的gravity一样,将元素对准中心。 为了显示差异,我将旧行注释掉并用新行替换:


 @Composable fun FormDemo() { Padding(10.dp) { // Column(crossAxisAlignment = CrossAxisAlignment.Start) { Column(crossAxisAlignment = CrossAxisAlignment.Center) { //  Text("Click the button below: ") HeightSpacer(10.dp) // Row { Row(mainAxisSize = FlexSize.Min) { //    Button(text = "Back") WidthSpacer(10.dp) Button(text = "Next") } } } } 

我们将成功:


中央对齐

使用crossAxisAlignment = CrossAxisAlignment.Center嵌套元素将水平居中。 我们还应该将Row参数设置为mainAxisSize = FlexSize.Min ,其行为与layout_width = wrap_content相似,因此由于默认的mainAxisSize = FlexSize.Max ,它不会在屏幕上mainAxisSize = FlexSize.Max ,其行为类似于layout_width = match_parent


2d。 备注


从上面的示例中我们可以看到,所有元素都是由单独的函数构成的: padding是单独的函数, spacer是单独的函数,而不是TextButtonColumn内部的属性。


诸如RecyclerViewConstraintLayout类的更复杂的元素正在开发中:因此,我无法在演示源中找到有关它们的示例。


3.样式和主题


您可能已经注意到,默认情况下,上面的按钮是紫色的。 这是因为它们使用默认样式。 让我们看看样式如何在Compose中工作。


在上面的示例中, FormDemo带有@Composable注释。 现在,我将展示如何在Activity使用此元素:


 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{ MaterialTheme { FormDemo() } } } } 

代替setContentView()函数,我们使用setContent() ,它是Compose.kt库中的扩展函数。


CraneWrapper包含Compose树,并提供对ContextDensityFocusManagerTextInputService


MaterialTheme允许您自定义元素的主题。


例如,可以将主题的原色更改为棕色,如下所示:


 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{ // MaterialTheme { MaterialTheme(colors = MaterialColors(primary = Color.Maroon)) { FormDemo() } } } } 

现在,我们的屏幕将如下所示:


栗色为原色

可以更改的其他颜色和字体: MaterialTheme.kt#57


Rally Activity提供了一个很好的示例,可以如何自定义主题: RallyTheme.kt的源代码


看什么/读什么


如果需要更多,可以根据此处说明组装示例项目。


正如Windows用户所写的那样,现在没有启动Compose的正式方法,但是kotlinlang Slack提供了一个非官方的指南


可以在#compose kotlinlang Slack频道中向开发人员询问有关Compose的问题。


在评论中保留其他链接-最有用的链接将在此处添加。


结论


该库的开发如火如荼,因此此处显示的任何接口均可能发生变化。 您还可以在源代码中学习很多东西,例如@Model和单向数据流(单向数据流)。 也许这是以后文章的主题。

Source: https://habr.com/ru/post/zh-CN461101/


All Articles