Android全新UI框架之Jetpack Compose入门基础

本文介绍了JetpackCompose,一种让Android原生开发采用声明式UI的方式,对比了其与传统XML开发的差异,强调了Compose的优势,包括API设计原则、Composable函数的作用以及与View的关系。同时,讲解了如何在现有项目中引入和使用Compose组件,如AndroidView的运用。
摘要由CSDN通过智能技术生成
  • Jetpack Compose是什么
    如果有跨端开发经验的同学,理解和学习compose可能没有那么大的压力。简单地说,compose可以让Android的原生开发也可以使用类似rn的jsx的语法来开发UI界面。以往,我们开发Android原生页面的时候,通常是在xml中画相关的UI控件,然后在activity中通过findViewById拿到相关的控件对象,接着根据业务需求调用该控件对象的相关API方法。这种方式官方称之为命令式UI。再加上大前端浪潮的兴起,React、Vue等声明式UI技术的的日益成熟,以往那套继承自View的组件体系已经越发难以维护(目前View.java已超过3万行代码),因此Compose这门技术就应运而生了。

  • Jetpack Compose的优势
    这点感兴趣的同学就到官网看下就行了,反正就是一堆好处。值得注意的是compose最低兼容到API21

  • Compose API设计原则
    由于Compose在编程范式上与传统视图体系有着根本的不同,在开始深入学习Compose之前,有必要对Compose API的设计原则做一个介绍。无论是Compose预置的Composable还是开发者自己定义的Composable,都应该遵守这些原则

    1. 一切皆为函数
      Compose声明式UI的基础是Composable函数Composable函数通过多级嵌套形成结构化的函数调用链,函数调用链经过运行后生成一颗UI视图树。视图树一旦生成便不可随意改变。视图的刷新依靠Composable函数的反复执行(重组)来实现。当需要显示的数据发生变化时,Compoable基于新参数再次执行,更新底层的视图树,最终完成视图的刷新。
      在这里插入图片描述
      Composable函数只能在Composable函数中调用,这与挂起函数只能在协程或其他挂起函数中调用类似,都是在编译期保证的。在Compose的世界中,一切组件都是函数,由于没有类的概念,因此不会有任何继承的层次结构,所有组件都是顶层函数,可以在DSL中直接调用。
    2. 组合优于继承
      Composable作为函数相互没有继承关系,这有利于促使开发者使用组合的视角去思考问题。
    3. 单一数据源
      在传统的命令行UI中(以EditText为例),文字的变化来源多处,有可能来自用户的输入,也可能来自代码某处的setText。状态变化可能不止一个来源,即所谓的多数据源。多数据源下的状态变化不容易跟踪,且会使后期难以维护。单一数据源决定了Composable数据流的单向流动,数据(name)总是自上而下(由父组件流向子组件)流动,而事件(onNameChange)总是自下而上(由子组件流向父组件)传递。
  • Compose与View的关系
    在传统视图体系中由View与ViewGroup构成视图树,而Compose中也有同样一颗视图树,它由LayoutNode构成,由Composition负责管理。
    在这里插入图片描述
    两种树的节点类型不同,但是它们并非全没关系,依然可以共存于一棵树中。就像DOM节点与View也不同,但是可以通过WebView显示在一棵树上,Compose也可以借助这样一个连接点挂载在View树上。使用Android Studio自带的Layout Inspector可以看到这个连接点就是ComposeView,它就是连接View与Compose的桥梁。
    在这里插入图片描述
    ComposeView有一个唯一子节点AndroidComposeView,它既是一个ViewGroup,也是LayoutNode视图树的持有者,它实现了LayoutNode视图结构与View视图结构的连接。既然AndroidComposeView已经承担了两套体系的连接,那为什么还要多一层ComposeView呢?
    ComposeView继承自AbstractComposeView,而后者有三个子类,分别对应着Activity窗口、Dialog窗口与PopupWindow窗口。Android平台存在所谓Window的概念,我们在很多场景下会有多窗口需求,例如在页面中弹出一个对话窗。AbstractComposeView的子类负责Android平台各类窗口的适配并生成对应的Composition, ComposeView作为其中一个子类负责Activity窗口的适配。总体来说,ComposeView负责对Android平台的Activity窗口的适配,AndroidComposeView负责连接LayoutNode视图系统与View视图系统。如此的职责划分可以实现上层视图适配与下层窗口适配逻辑的解耦。

Composition是视图树的创建者。从Composable函数到视图树的生成经历这个过程:
第一步Composable函数执行后填充SlotTable, SlotTable中记录着Composable执行过程的状态信息;
第二步基于SlotTable生成和更新LayoutNode视图树。Composition负责从Composable执行到视图树生成(更新)的整个过程。

ComposeView接入View视图后,内部的UI工作都在Compose侧闭环处理,来自AndroidComposeView的绘制、测量布局与手势事件分发等都下沉到LayoutNode去完成。ComposeView作为View可以挂载到原有View视图树中的任意位置。因此一个传统视图项目可以通过ComposeView阶段性地接入Compose。一个纯Compose页面就是将ComposeView直接挂载到ContentView上面。

  • 不只是Android UI框架
    Compose还包含一些其他的库,如下图所示:
    在这里插入图片描述
    Compose从上到下分为四层,每一层都可以被单独使用,在不同维度提供能力支持。可以只使用Compose的Runtime层构建任何基于数据驱动能力的系统或类库。在这样清晰的分层结构下,我们甚至可以隔离那些平台相关代码,自底向上自己来实现跨平台的UI系统。
    在这里插入图片描述
  • Compose开发环境搭建
    1. 创建一个新的Compose项目
      这个比较简单,使用AndroidStudio创建项目时,选择compose项目,然后无脑下一步即可,如下图所示:
      在这里插入图片描述
    2. 已有项目引入Compose
      按照下面步骤改造已有项目:
      • 在工程中引入Compose相关依赖:
        dependencies {
            implementation platform('androidx.compose:compose-bom:2022.10.00')
            implementation 'androidx.compose.ui:ui'
            implementation 'androidx.compose.material3:material3'
        }
        
      • 在build.gradle文件的android闭包中添加如何下配置:
            buildFeatures {
                compose true
            }
            composeOptions {
                kotlinCompilerExtensionVersion '1.3.2'
            }
            packagingOptions {
                resources {
                    excludes += '/META-INF/{AL2.0,LGPL2.1}'
                }
            }
        
      • 修改相关的xml布局文件
        <?xml version="1.0" encoding="utf-8"?>
        <androidx.compose.ui.platform.ComposeView xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/root"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
        
        </androidx.compose.ui.platform.ComposeView>
        
      • 在activity中查找该View并使用setContent即可
        class MainActivity : AppCompatActivity() {
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(R.layout.activity_main)
                findViewById<ComposeView>(R.id.root).setContent { 
                    Text(text = "Hello Compose")
                }
            }
        }
        
    3. 在Compose中使用View组件
      不少功能性的传统视图控件在Compose中没有对应的Composable实现,例如SurfaceView、WebView、MapView等。因此在Compose中可能会有使用传统View控件的需求。Compose提供了名为AndroidView的Composable组件,允许在Composable中插入任意基于继承自View的传统视图控件。
      class MainActivity : ComponentActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContent {
                  AndroidView(factory = { context ->
                      WebView(context).apply {
                          settings.javaScriptEnabled = true
                          webViewClient = WebViewClient()
                          loadUrl("https://www.baidu.com/")
                      }
                  }, modifier = Modifier.fillMaxSize())
              }
          }
      }
      
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值