正如2019年Android Dev Summit所宣布的那样,Jetpack compose可供开发人员预览。它的声明式UI功能一直在城镇中引起轰动。
我最近开始尝试Jetpack Compose,实际上我开始喜欢它! 首先,我要说我实际上不太喜欢Flutter。 尽管它具有状态管理的所有功能,声明性UI,但对于DART,它仍然感觉很原始。
在有关Jetpack Compose的介绍性文章中,我们将了解什么是Compose,并构建一个简单的应用程序来了解它。
Jetpack Compose是Android Jetpack中的一个库,使开发人员能够构建可组合的功能。 将可组合函数视为返回View的常规Kotlin函数。
调用此函数后,会将视图添加到布局中。 它们使用@Composable注释进行注释。 让我们看看下面的示例函数
@Composable fun Greeting(name: String) {
Text(
text = "Hello $name!" ,
modifier = Spacing( 24 .dp)
) }
我们还可以具有多个嵌套视图,如下所示:
@Composable fun Content(counterState: State = State()) {
Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
Column(modifier = Flexible(1f), crossAxisAlignment = CrossAxisAlignment.Center, mainAxisAlignment = MainAxisAlignment.Center) {
}
Row(modifier = ExpandedWidth, mainAxisAlignment = MainAxisAlignment.End) {
}
} }
如果您使用过Flutter ,这似乎与您非常相似。 是的! Jetpack Compose在本机类固醇上感觉像振颤……。
Jetpack Compose的一些最佳功能是:
- 构建声明性UI。
- 在Android Studio 4中增加了对即时预览布局的支持。
- 视图可以分解为功能,并且可以在多个地方使用。
- @Model数据类的状态管理功能非常强大。 我们将在接下来的部分中对此进行更多研究。
但这不仅是阳光和彩虹。 我也对撰写有一些担忧,例如:
- UI和逻辑耦合在一起。 我觉得因为Jetpack Compose会将UI移到kotlin文件,所以这可能导致代码耦合。
- 嵌套:我遇到了颤振的问题,即使在Compose中也不会变得更好。 也许只有我一个人,但是多个嵌套花括号的想法对我来说却是艰巨的。
尽管如此,它还是在这里,它是Google推荐的。 因此,让我们看看使用android中的Jetpack Compose开发一个简单的hello world kinda应用程序的感觉。 如下所示:
![](https://i-blog.csdnimg.cn/blog_migrate/54a2f102040f22fb9501743d6047c8f8.png)
您将无法在当前版本的Android Studio上使用Compose。 为此,您需要从canary渠道安装AS 4.0。
MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
setContent {
MyApp {
Content()
}
}
} }
要更改为金丝雀频道,请按照以下步骤操作:
- 转到“设置”(Win)/“首选项”(Mac)。
- 然后转到系统设置->更新
- 从那里,您可以将稳定频道更改为金丝雀频道。
然后检查更新。 它将要求您下载AS 4.0 Preview。 因此,下载并安装它。 现在,我们将创建一个用于撰写的新项目。
转到文件->新建->新建项目,然后选择清空撰写活动。 从那里开始,通常按照向导进行操作,然后选择完成。
您会注意到的第一件事是setContent函数现在接受lambda 。 这就是Jetpack Compose的工作方式。 函数将可组合函数作为lambda接受,并将其属性作为参数。
如果您通过按Cmd + Click深入研究代码,您会注意到setContent现在接受可组合函数作为参数。 可组合参数也用@Composable注释。
回到我们的代码,我们传入了MaterialTheme,这表示我们的应用将使用Material Design构建。 最后,我们传递了Greeting组合物,该组合物本质上是TextView。
进一步讲,您会注意到一个用@Preview注释的方法。
@Preview ( "MyScreen preview" ) @Composable fun MyPreview() {
MyApp {
Content()
} }
这表明必须使用该方法预览布局。 您可以在右侧窗口窗格中看到预览。
首先,让我们摆脱将应用程序主题设置为单独功能的责任。
@Composable fun MyApp(children: @Composable () () -> Unit) {
MaterialTheme {
Surface(color = Color.White) {
children()
}
} }
注意:此函数不在MainActivity.kt类中
MyApp()是一个可组合函数,它接受另一个可组合函数。 我们还将使用Surface(这是Compose UI工具包中的另一个元素)设置应用程序的背景。 最后,我们传入收到的lambda。 这将确保我们将所有子级封装在此主题内。
接下来,让我们开始向屏幕添加一些内容。 创建另一个名为Content()的函数,该函数是可组合的函数。
要将文本放置在屏幕中央,请创建一列 ,以填充屏幕的整个高度。 这将是根容器。
@Composable fun Content() {
Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
} }
将列和行仅视为LinearLayout ,其方向分别为Vertical或Horizontal。 他们一一堆叠孩子。
行和列有两个轴,主轴和交叉轴。 下图更好地说明了这一点:
![](https://i-blog.csdnimg.cn/blog_migrate/b8c1876e6b46687a07ac6bb86fce79f2.png)
接下来,我们需要创建一个容器来添加文本。 该容器仅包含文本。 展开此容器以填充屏幕的整个高度。 我们通过传递ExpandedHeight修饰符来实现。
@Composable fun Content() {
Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
Column(modifier = Flexible(1f), crossAxisAlignment = CrossAxisAlignment.Center, mainAxisAlignment = MainAxisAlignment.Center) {
Text(text = "I've been clicked 0 times!" )
}
} }
对于第二列,我们添加了Flexible()作为修饰符。 这告诉该列以权重1覆盖屏幕。 这可以认为是权重为1的垂直LinearLayout。
同样,在我们的根Column中,我们将添加一个MainLine对齐到末尾的行。 这将帮助我们将按钮对齐到末尾。 最后,我们添加按钮。 从计数器功能返回按钮。
@Composable fun Content(counterState: State = State()) {
Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
Column(modifier = Flexible(1f), crossAxisAlignment = CrossAxisAlignment.Center, mainAxisAlignment = MainAxisAlignment.Center) {
Text(text = "I've been clicked ${counterState.count} times!" )
}
Row(modifier = ExpandedWidth, mainAxisAlignment = MainAxisAlignment.End) {
Padding(padding = 16 .dp) {
Counter(counterState)
}
}
} }
现在是时候在用户单击按钮时进行一些操作了。 本质上,无论何时单击按钮,我们都希望增加计数器。
为此,我们将计数器的当前状态存储在包含count变量的数据类中。
@Model class State(var count: Int = 0 )
注意@Model批注。 这表明将观察该数据类的更改。 每当数据更改时,从@Model注释类读取数据的可组合函数将重新组合。 从而更新UI。
现在,我们将在Content函数中传递此State对象的实例。 我们将更改我们的消息以包括两者之间的计数。
@Composable fun Content(counterState: State = State()) {
Column(modifier = ExpandedHeight, crossAxisAlignment = CrossAxisAlignment.Center) {
Column(modifier = Flexible(1f), crossAxisAlignment = CrossAxisAlignment.Center, mainAxisAlignment = MainAxisAlignment.Center) {
Text(text = "I've been clicked ${counterState.count} times!" )
}
Row(modifier = ExpandedWidth, mainAxisAlignment = MainAxisAlignment.End) {
Padding(padding = 16 .dp) {
Counter(counterState)
}
}
} }
注意:我们使用默认参数作为State类的实例,因此可以不使用任何参数来调用Content方法。
接下来,让我们向按钮添加功能以增加计数器。 在Counter函数中传递状态对象。 我们的按钮接受onClick的lambda。 我们将传递一个lambda来增加计数器。 这将导致文本重新组成并更新UI。
@Composable fun Counter(state: State) {
Button(text = "Click Me!" , style = ContainedButtonStyle(), onClick = {state.count++}) }
我故意选择创建此计数器应用。 原因是它类似于您在创建新的flutter项目时预先构建的应用程序!
我想对比一下Flutter vs Jetpack Compose中构建类似应用程序的差异。 在Compose中构建UI很高兴。 远远超过Flutter。 但这可能是我在Kotlin上开发本机应用程序时的偏见。
您对Jetpack Compose有什么经验? 在下面的评论中提及! 让我们聊天
翻译自: https://www.javacodegeeks.com/2019/11/android-jetpack-compose-once-and-for-all.html