从Windows到Web,到Android,到iOS,我们编写应用 (App) 最初的方式都是命令式的 (Imperative Style) 。但随着声明式 (Declarative Style) 的出现,情况正在发生极速的变化。我们先看看命令式和声明式分别怎么写UI。

命令式 vs 声明式

命令式 (Imperative Style)

命令式的方式是一种自然而然想到的方式,我们写代码构建整个UI (view tree),在需要更新UI时 (比如获取到网络数据后或者用户改变UI元素后) 从view tree里查找到对应的元素,再更新它。比如在Android开发中,我们通过findViewById查找到某文本元素,再给它设置显示的内容:


TextView tv = findViewById(R.id.text_view);
tv.setText("Hello World");

声明式 (Declarative Style)

命令式的方式是一种最朴素的方式,它要求我们针对每一次UI的变更都亲自写代码修改view tree,且这些代码分散在各个地方。那么我们有没有方法把我们从对view tree的频繁操作中解放出来呢?有。Facebook的React框架就是一个知名的先驱。声明式的方式集中在一个地方声明UI的结构,UI的变化通过数据来驱动。我们只需要修改数据,剩下的修改view tree的工作交给框架来做。

声明式发展历程

其实声明式的UI布局方式已经有比较长的历史,下面简单介绍一些比较知名的

Facebook React

前端开发在React之前,比较常用的是jQuery这种命令式的框架。下面是一个jQuery的例子,用ajax发起一个网络请求,请求返回结果后在DOM树里搜索到节点 ($("#weather-temp")) ,再将结果设置给节点显示出来。


$.ajax({url: "/api/getWeather",data: {zipcode: 97201},success: function( result ) {$("#weather-temp").html( "<strong>" + result + "</strong> degrees" );}
});

Facebook内部从2011年开始开发FaxJS,也就是React的原型,并于2013年开源了React。下面是一个React声明式UI的例子


class MarkdownEditor extends React.Component {constructor(props) {super(props);this.md = new Remarkable();this.handleChange = this.handleChange.bind(this);this.state = { value: 'Hello, **world**!' };}handleChange(e) {this.setState({ value: e.target.value });}getRawMarkup() {return { __html: this.md.render(this.state.value) };}render() {return (<div className="MarkdownEditor"><h3>Input</h3><label htmlFor="markdown-content">Enter some markdown</label><textareaid="markdown-content"onChange={this.handleChange}defaultValue={this.state.value}/><h3>Output</h3><divclassName="content"dangerouslySetInnerHTML={this.getRawMarkup()}/></div>);}
}root.render(<MarkdownEditor />);

渲染效果:

我们将某个Component的UI描述全部放在render方法里,这个Component有它自己的状态 (state)。当用户在textarea输入内容时,handleChange会被调用,它会从textarea取出当前值,赋给value这个state变量,调用setState方法告诉React框架需要更新UI,然后框架就会完成剩下的所有工作。对开发者来说非常的简单高效。

Facebook React Native

Facebook在2015年开源了React Native这个跨平台的框架,它可以让你通过前端技术栈开发Android和iOS应用。它声明UI的方式和React一模一样,如下所示


import React from 'react';
import {Text, View} from 'react-native';
import {Header} from './Header';
import {heading} from './Typography';const WelcomeScreen = () => (<View><Header title="Welcome to React Native"/><Text style={heading}>Step One</Text><Text>Edit App.js to change this screen and turn itinto your app.</Text><Text style={heading}>See Your Changes</Text><Text>Press Cmd + R inside the simulator to reloadyour app’s code.</Text><Text style={heading}>Debug</Text><Text>Press Cmd + M or Shake your device to open theReact Native Debug Menu.</Text><Text style={heading}>Learn</Text><Text>Read the docs to discover what to do next:</Text></View>
);

Facebook Litho

Facebook在2017年开源了Litho这个高性能的Android UI开发框架,在开源之前已在内部主要App广泛使用,如Facebook等。受React的影响,它也采用了声明式的UI布局方式。下面是一个例子

class PostStyledKComponent(val post: Post) : KComponent() {override fun ComponentScope.render(): Component {return Column {child(Row(alignItems = YogaAlign.CENTER, style = Style.padding(all = 8.dp)) {child(Image(drawable = drawableRes(post.user.avatarRes),style = Style.width(36.dp).height(36.dp).margin(start = 4.dp, end = 8.dp)))child(Text(text = post.user.username, textStyle = Typeface.BOLD))})child(Image(drawable = drawableRes(post.imageRes),scaleType = ImageView.ScaleType.CENTER_CROP,style = Style.aspectRatio(1f)))}}
}

渲染效果:

Google Flutter

Google在2018年发布了Flutter的第一个稳定版本v1.0.0。它采用了声明式的布局方式,下面是一个简单的例子

class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Welcome to Flutter',home: Scaffold(appBar: AppBar(title: const Text('Welcome to Flutter'),),body: const Center(child: Text('Hello World'),),),);}
}

Apple SwiftUI

Apple在2019年发布了SwiftUI的第一个版本,它让你用声明式的方式来写iOS应用。下面是一个简单的例子

import SwiftUIstruct AlbumDetail: View {var album: Albumvar body: some View {List(album.songs) { song in HStack {Image(album.cover)VStack(alignment: .leading) {Text(song.title)Text(song.artist.name).foregroundStyle(.secondary)}}}}
}

Google Jetpack Compose

Google在2021年7月发布了Jetpack Compose的第一个稳定版本v1.0,像Flutter一样采用声明式UI布局方式,但Compose的设计比Flutter更合理一些。在Flutter里,你要给一个Widget设置宽高等属性都需要在外面套一层Container来实现,这非常的臃肿,而其它声明式的框架,包括Compose,大都可以通过节点的属性来设置。下面是一个Compose的简单例子

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp@Composable
fun MessageCard(msg: Message) {// Add padding around our messageRow(modifier = Modifier.padding(all = 8.dp)) {Image(painter = painterResource(R.drawable.profile_picture),contentDescription = "Contact profile picture",modifier = Modifier// Set image size to 40 dp.size(40.dp)// Clip image to be shaped as a circle.clip(CircleShape))// Add a horizontal space between the image and the columnSpacer(modifier = Modifier.width(8.dp))Column {Text(text = msg.author)// Add a vertical space between the author and message textsSpacer(modifier = Modifier.height(4.dp))Text(text = msg.body)}}
}

渲染效果:

展望

我们看到2017年的Litho,2018年的Flutter,2019年的SwiftUI,2021年的Jetpack Compose都采用了声明式的UI布局方式,已呈燎原之势,声明式的UI布局方式未来会像前端领域的React一样成为主流吗?

声明式UI是否会成为Android开发的主流?相关推荐

  1. Android声明式UI框架 Litho 初探——基础使用

    初衷 Litho作为一个高性能的UI引擎,学习曲线还是比较高的,但是在国内能用的资料非常少(大部分都是相互复制的"Hello Word"教程),国外除了Litho自己的文档外,也没 ...

  2. 声明式UI(Declarative)和命令式(Imperative)UI的差异?

    声明式UI(Declarative)和命令式(Imperative)UI的差异? 声明式 这里应该展示一个缩小50%的,旋转180的图片.可以表示为,what should happen. 命令式 需 ...

  3. Android声明式UI框架-Litho-初探——基础使用篇

    初衷 Litho作为一个高性能的UI引擎,学习曲线还是比较高的,但是在国内能用的资料非常少(大部分都是相互复制的"Hello Word"教程),国外除了Litho自己的文档外,也没 ...

  4. Android的 API 框架,Android 声明式 UI 框架 Litho 初探 —— Sections API

    在最开始入门介绍中,我们曾经用SingleComponentSection完成了一个简单的列表,当时的做法是使用 for 构造出了多个子Component.其实在 Litho 中提供了一个性能更好的方 ...

  5. 告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南

    什么是Jetpack Compose? Jetpack Compose是Android的新声明式UI框架.长期以来, Android 开发人员习惯于使用带有状态视图的xml编写UI,这些状态视图通过逐 ...

  6. 2017-05-04-Facebook出品的Android声明式开源新框架Litho文档翻译-总览和导航

    本文是博主转发自己的博客文章至CSDN. 欢迎点击博主的博客查看原文,体验更好的浏览感受. 欢迎转载,转载请标明出处. 今天逛github发现facebook开源了一个新框架Litho,大概看了一下介 ...

  7. Jetpack Compose--声明式UI替代传统命令式UI的新产品

    Jetpack Compose--声明式UI替代传统命令式UI的新产品 声明式UI与传统UI创建方式(命令式UI)的区别 Jetpack Compose的优势 Jetpack Compose的缺点 最 ...

  8. 为什么说 Compose 的声明式代码最简洁 ?Compose/React/Flutter/SwiftUI 语法对比

    前言 Comopse 与 React.Flutter.SwiftUI 同属声明式 UI 框架,有着相同的设计理念和相似的实现原理,但是 Compose 的 API 设计要更加简洁.本文就这几个框架在代 ...

  9. 阿里Android开发规范:安全与其他

    以下内容摘自 阿里巴巴Android开发手册 我们的目标是: 防患未然,提升质量意识,降低故障率和维护成本: 标准统一,提升协作效率: 追求卓越的工匠精神,打磨精品代码. [强制]必须遵守,违反本约定 ...

最新文章

  1. 如何在指定文件夹下进入jupyter notebook
  2. fancybox 在打开窗口前 先执行 js脚本,fancybox设置只能通过右上角关闭,fancybox遮罩层关闭...
  3. jQuery里面的addClass讲解
  4. scale html 浏览器,javascript中scale怎么使用?
  5. 北邮计算机学不学单片机,北邮小学期PC单片机.docx
  6. 戴帽子对眼睛是否有好处
  7. 到无限(溪流)和超越!
  8. .NET下实现分布式缓存系统Memcached
  9. 如何合理地决定线程池大小?
  10. 麦迪逊大学计算机科学咋样,威斯康星大学麦迪逊分校计算机专业排名
  11. 利用Easy-Rules实现动态业务规则
  12. Javascript中的执行环境及作用域
  13. python numpy安装失败_【Python】pip安装numpy安装到一半失败解决办法
  14. 500强企业专家级面试果然是噩梦级,吐血分享成功经验
  15. 三阶魔方层先还原方法图解
  16. 网络直播算是计算机技术吗,计算机网络技术与电视直播新闻的融合发展
  17. 【继承系列】JS中的组合继承
  18. 智能制造系统架构和标准体系结构
  19. 以太网工业RFID读写器|读卡器CK-FR12-E01接线说明与PLC组网方案
  20. 最高要价 8888元,小米 11 邀请函现身闲鱼;马斯克曾考虑把特斯拉卖给苹果却被拒;我国区块链专利全球居首 | EA周报...

热门文章

  1. 【运行报错】Redis:Operation against a key holding the wrong kind of value
  2. R语言︱贝叶斯网络语言实现及与朴素贝叶斯区别(笔记)
  3. 网址被QQ拦截后应该怎么做才可能尽快解除拦截
  4. 作为反馈电路有很好的相位裕度、但很差的稳定性能的一个例子
  5. iOS中mmap的应用
  6. Springboot整合Elasticsearch 报错availableProcessors is already set to [4], rejecting [4]
  7. Java命令简易入门-2:javac与java命令之一(javac)
  8. [人体运动分析]关节中心的计算
  9. 数据结构-火车车厢重排问题(队列实现)
  10. 当游戏爱上MongoDB–参会赢Kindle