Android Jetpack Compose 超快速上手指南

Compose 介绍

Compose库是用响应式编程的方式对View进行构建,可以用更少更直观的代码,更强大的功能,能提高开发速度(可以参考几乎一模一样的Flutter,开发速度确实很快)。

Jetpack Compose对于没有接触过声明式UI的小伙伴可能会学习曲线有点陡峭,对于已经能熟练开发Flutter应用的小伙白来说几乎没有难度。(Compose就是参考flutter的模式开发的,代码中还可以看到Flutter的相关注释)

这篇文章不回去解释过多的原理与技巧,只要是让你能够快速上手开发项目。

目前Jetpack ComposeAlpha 版。所以需要在 Android StudioCanary 版本才能体验。下载 ANDROID STUDIO CANARY 版

1. 创建 Jetpack Compose 项目

Android Studio Canary 版本中已经提供了 Compose 的模板,在创建项目时选择 Empty Compose Activity 模板即可。

至此,就完成一个 Compose 项目的创建。除此之外,我们也可以选择导入 Jetpack Compose 示例应用,操作步骤参照 Jetpack Compose Sample 操作步骤

2. Compose 函数使用

Compose 是一种以函数为依托的声明式 UI 构建方式。比如在 MainActivity.kt 中显示一个文本。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello Compose!")
        }
    }
}

这个与使用 XML 布局的方式差别很大,setContent 块定义了 Activity 的布局。我们不使用 XML 文件来定义布局内容,而是调用一个 Compose 函数,比如上面的 Text 函数。然后 Jetpack Compose 使用自定义 Kotlin 编译器插件将这些 Compose 函数转换为应用的界面元素。

2.1 Compose 函数

Jetpack Compose 是围绕 Compose 函数构建的,在开发时只需描述应用界面的样式布局和数据依赖关系,而不必关注界面的构建过程。给一个函数添加 @Composable 注解即创建了一个 Compose 函数。注意,Compose 函数只能在其他 Compose 函数的范围内调用。 下面我们将上面示例中的 Text 移动到自定义的 Compose 函数中。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            HelloCompose()
        }
    }

    @Composable
    fun HelloCompose() {
        Text("Hello Compose!")
    }
}
2.3 设置点击监听

除了使用 Text 函数,还有其它的基础函数供我们使用,比如 ButtonImage 等。那么如何给 UI 控件设置点击监听呢?在 Compose 框架中提供了两种方式:

  • 对于类似 Button 函数的这种,提供了 onClick 函数式接口供外部设置点击监听;
  • 对于类似 Text 函数这种,没有提供显式接口设置的,通过 Modifier 类设置点击监听;

Button 函数设置点击事件

@Composable
fun TextButton() {
    Button(
        onClick = {
            Log.d("Andoter", this.javaClass.name)
            Toast.makeText(this@MainActivity, "Button 点击", Toast.LENGTH_SHORT).show()
        }
    ) {
        Text(text = "Hello Compose!", color = Color.Red)
    }
}

通过设置 onClick 函数即可实现点击实现,注意 Button 函数本身没有设置文本内容,需要通过 Text 函数设置显示文本内容。

Text 函数设置点击事件

@Composable
fun ClickedText() {
    val modifier = Modifier.clickable(onClick = {
        Log.d("Andoter", this.javaClass.name)
        Toast.makeText(this@MainActivity, "Button 点击", Toast.LENGTH_SHORT).show()
    })

    Text(text = "Hello Compose!",modifier = modifier.padding(10.dp))
}

通过 Modifier.clickable 的方式实现设置点击事件。Modifier 类不仅能够设置点击事件,还能够设置控件的布局属性。

  • clickable() :设置点击监听
  • padding() :在元素周围留出空间
  • fillMaxWidth() :使可组合项填充其父项给它的最大宽度
  • preferredSize() :指定元素的首选宽度和高度
2.4 预览

Compose 框架中为 Compose 函数提供预览能力,通过给 Compose 函数添加 @Preview 注解即可进行预览。在实际的开发中,预览函数不要发布到线上,所以最佳做法是单独创建不会被应用调用的预览函数用于查看实际效果,专门的预览函数可以提高性能,并且有利于以后更轻松地设置多个预览。

3. 布局

Jetpack Compose 中一切的元素都是围绕 Compose 函数展开,所以布局也是通过对应的内置 Compose 函数实现。

3.1 ColumnRow

二者的特点:

  • Column:使元素按照竖直方向排列;
  • Row:使元素按照水平方向排列;
  • Stack:将一个元素放在另一个元素上。

这里我们以 Column 函数作为示例。

@Preview
@Composable
fun MultiText() {
    Text(text = "Hello Compose!")
    Text("Ant 学习 Compose!")
}

@Preview
@Composable
fun ColumnText() {
    Column {
        Text(text = "Hello Compose!")
        Text("Ant 学习 Compose!")
    }
}

通过 Column 可将组件按照竖直方向排列,预览效果对比:

3.2 ScrollableRowScrollableColumn

使用 ScrollableRowScrollableColumn 可使 RowColumn 内的元素滚动。

@Composable
fun ProductList() {
    ScrollableColumn(Modifier.fillMaxSize()) {
        listOf("Ant", "Andoter", "小伟").forEach { value ->
            ProductDetailView(value)
        }
    }
}

@Composable
fun ProductDetailView(text: String) {
    val image = imageResource(id = R.drawable.header)
    Column(modifier = Modifier.padding(16.dp)) {
        val imageModifier = Modifier
            .preferredHeight(180.dp)
            .clip(shape = RoundedCornerShape(5.dp))
            .fillMaxWidth()
            .clickable(onClick = {
                Log.d("Ant", "click");
            })
        Image(image, modifier = imageModifier, contentScale = ContentScale.Crop)
        Spacer(modifier = Modifier.preferredHeight(16.dp))
        Text("Hello Compose!")
    }
}

4. Compose 界面结构

通过上面的介绍,对 Compose 有了一个初步的认识,那么 Compose 函数如何绘制在屏幕上的呢?以什么样的形式展示的呢?我们使用 Layout Inspector 工具查看一个 Compose 页面。

[图片上传中…(image-58ed43-1618911825900-1)]

通过左侧的布局结构可以发现,Compose 框架中已经废弃原有的 View 体系中的控件(TextViewButtonImageView 等),而是使用 AndroidComposeView(继承 ViewGroup)、ViewLayerContainer(继承 ViewGroup)和 ViewLayer(继承 View) 控件实现,其中 ViewLayer 代表每个 View 控件视图。

查看 ViewLayer 的调用关系,可以得到视图的生成关系:LayerWrapperAndroidComposeView -> ViewLayer

5. Compose 对业务的影响

Jetpack Compose 是一个适用于 Android 的新式声明性界面工具包,同时点击监听的设置方式也发生较大变化,那么对于我来说,最直观的业务影响是无法继续使用原有的插码技术进行点击事件的采集。这块需要进行调研适配。

上面提到设置点击的两种方式,本质上都是通过 Modifier 进行实现,来看下面的一个例子。

@Composable
fun ClickedText() {
    val modifier = Modifier.clickable(onClick = {
        Log.d("Andoter", this.javaClass.name)
        Toast.makeText(this@MainActivity, "Button 点击", Toast.LENGTH_SHORT).show()
    })

    Text(text = "Hello Compose!", modifier = modifier.padding(10.dp))
}

通过 Modifier 给一个 Text 设置点击监听,在点击的时候弹出一个 Toast。反编译看看最后的实现。

/* access modifiers changed from: package-private */
@Metadata(mo23161bv = {1, 0, 3}, mo23164k = 3, mo23165mv = {1, 4, 0})
/* compiled from: MainActivity.kt */
public final class MainActivity$TextButton$1$1 extends Lambda implements Function0<Unit> {
    private final /* synthetic */ MainActivity $this;

    /* JADX INFO: super call moved to the top of the method (can break code semantics) */
    MainActivity$TextButton$1$1(MainActivity mainActivity) {
        super(0);
        this.$this = mainActivity;
    }

    @Override // kotlin.jvm.functions.Function0
    public final void invoke() {
        Log.d(LiveLiterals$MainActivityKt.INSTANCE.mo17059x27db7fde(), this.$this.getClass().getName());
        Toast.makeText(this.$this, LiveLiterals$MainActivityKt.INSTANCE.mo17064x88044b3e(), 0).show();
    }
}

Kotlin 经过处理最终是转换成一个继承 Lambda 并实现 Fuction0 接口的类来托管实现点击监听。这样我们就可以总结出 Hook 条件:

  • kotlin.jvm.internal.Lambda 的子类
  • 实现 kotlin.jvm.functions.Function 接口
  • publicfinal 修饰符的 invoke 方法

尽管 Hook 点找到了,但是目前还无法突破获取对应的 View,依托 View 读取的属性就无法获取。希望可以一起跟你探讨下。

6. 总结

长期以来,Android 视图层次结构一直可以表示为界面微件树。界面更新方式是使用 findViewById() 等函数遍历树,这种手动操纵视图的方式会提高出错的可能性。在过去的几年中,移动端已开始转向声明性界面模型,比如 FlutterSwift UI,所以 Jetpack Compose 框架应该也是后续发展的一个方向。

客观地讲,Compose 确实是一套比较难学的东西,因为它毕竟太新也太大了,它是一个完整的、全新的框架,确实让很多人感觉「学不动」,这也是个事实。

那怎么办呢?学不动怎么办呢?

如果你是因为缺少学习资料,而我正好薅到这本谷歌内部大佬根据实战编写的《Jetpack Compose 最全上手指南》,从入门到精通,教程通俗易懂,实例丰富,既有基础知识,也有进阶技能,能够帮助读者快速入门,是你学习Jetpack Compose的葵花宝典,快收藏起来!!!

第一章 初识 Jetpack Compose

1. 为什么我们需要一个新的UI 工具?

2. Jetpack Compose的着重点

  • 加速开发
  • 强大的UI工具
  • 直观的Kotlin API

3. API 设计

4. Compose API 的原则

  • 一切都是函数
  • 顶层函数(Top-level function)
  • 组合优于继承
  • 信任单一来源

5. 深入了解Compose

  • Core
  • Foundation
  • Material

6. 插槽API

第二章 Jetpack Compose构建Android UI

1. Android Jetpack Compose 最全上手指南

  • Jetpack Compose 环境准备和Hello World
  • 布局
  • 使用Material design 设计
  • Compose 布局实时预览
  • ……

2. 深入详解 Jetpack Compose | 优化 UI 构建

  • Compose 所解决的问题
  • Composable 函数剖析
  • 声明式 UI
  • 组合 vs 继承
  • 封装
  • 重组
  • ……

3. 深入详解 Jetpack Compose | 实现原理

  • @Composable 注解意味着什么?
  • 执行模式
  • Positional Memoization (位置记忆化)
  • 存储参数
  • 重组
  • ……

第三章 Jetpack Compose 项目实战演练(附Demo)

1. Jetpack Compose应用1

  • 开始前的准备
  • 创建DEMO
  • 遇到的问题

2. Jetpack Compose应用2

3. Jetpack Compose应用做一个倒计时器

  • 数据结构
  • 倒计时功能
  • 状态模式
  • Compose 布局
  • 绘制时钟

4. 用Jetpack Compose写一个玩安卓App

  • 准备工作
  • 引入依赖
  • 新建 Activity
  • 创建 Compose
  • PlayTheme
  • 画页面
  • 底部导航栏
  • 管理状态
  • 添加页面

5. 用Compose Android 写一个天气应用

  • 开篇
  • 画页面
  • 画背景
  • 画内容
  • ……

6. 用Compose快速打造一个“电影App”

  • 成品
  • 实现方案
  • 实战
  • 不足
  • ……

文章篇幅有限,仅截图展示部分内容,需要完整版的朋友可以【点击此处】免费领取。

猜你喜欢

转载自blog.csdn.net/m0_57081622/article/details/115914763