写点什么

实战 Kotlin@Andorid(二):界面构建与扩展方法

  • 2016-05-02
  • 本文字数:2491 字

    阅读完需:约 8 分钟

版权声明

原作者:Doug Stevenson

译者:程大治

本文由原作者授权翻译并发布,首发于移动开发前线公众号,未经允许禁止转载。

这是实战 Kotlin@Android 的第二部分,如果你还没读过第一部分,建议先阅读第一部分实战Kotlin@Android(一):项目配置和语言转换

在前面的文章中我们使用Kotlin 中type-safe builder 模式写了一个还算有用的v 方法,它可以构建任意Android View 实例。

我们可以在其他Kotlin 代码中调用这个方法来创建并初始化任何类型的View:

这真的实用吗?

现在我们要创建一个很简单的layout,它包含两个TextView。在XML 可以这样表示:

我们可怜的v 方法不能一下子创建这么多,不过只需借助一点帮助。我们需要再写一个能够将View 添加至父View(LinearLayout, RelativeLayout)的方法。我们现在写一个新的v 方法。

这个方法与原本的v 方法几乎一摸一样,区别只在第一个参数上:不再是Context, 变成了ViewGroup 类型。这个新的v 方法需要持有父ViewGroup,以便将新创建的View 对象在初始化并返回之前添加进其中。而新的v 方法又能通过ViewGroup 来获取Context 以初始化View,这样就不用再传入Context 对象了。

现在我们看一下新的v 方法如何与旧的协作来构建上述View 层级。

这里Kotlin 代码会像XML 一样嵌套,非常好看。

在上一部分中说过,Kotlin lambda with receiver 可以在lambda 内部以this 关键字引用receiver 对象。在上面的例子中,在外部v 的lambda 中receiver 是LinearLayout,它作为第一个参数被传入了两个内部v 方法(刚写的v 方法)。因为LinearLayout 是ViewGroup 的子类,Kotlin 知道我们在调用新写的v 方法,因为旧的需要传入Context。

通过这两个兄弟v 方法我们可以动态地、精确地创建嵌套View,其中的ViewGroup 和View 的具体类型均无限制。现在我们已经可以发现这种表述性的创建方式与XML 有些相似,而在后续的文章中,我们也将发现Kotlin 的速度要快一些。

提升空间

Kotlin 的 type-safe builder 模式起了很大的作用,但是在很多时候,Kotlin 还是比 XML 复杂不少。比如在 Kotlin 中当我们想设置一个 TextView 的 maxWidth 属性为 120dp 时:

而在 XML 中,只需要:

本来是为了简化工作写的 v 方法一下变麻烦了。

这里需要将 dp 转化为 px 的简便方法

我在这里想要一个方法可以将 dp 转化为像素,然后上面的代码最好能长这样:

这里的方法可以接收一个以 dp 为单位的值,然后返回当前设备下转化成像素的值。不过为什么要叫这个方法 dp_i 而不是 dp 呢?在 Android 中有时会返回 float 而有时会返回 int,我也不想再自己进行转换,所以就给两种返回类型都写一个方法:"dp_i"和“dp_f”。

但在这里仍有问题。如果你看一下刚才很丑的那段代码,会发现计算像素值时需要 Context 对象。我可不想每次调用 dp_i 方法都传入 Context 作为参数,所以在这里要用到 Kotlin 的另一个技能:extension functions 扩展方法。让我们直接看一下扩展方法长什么样:

扩展方法如何工作?

你可能注意到的第一个点就是方法的前缀。你可能本以为第一个方法应该是 dp_f,结果是 View.dp_f。这是 Kotlin 中针对扩展方法的一个特殊语法。这里将一个类名和一个方法名以点连接,而意思就是告诉 Kotlin 我们要给 View 类添加两个新方法"dp_i",“dp_f”。这样使用扩展方法有几点好处:

第一,在扩展方法内作为类的成员可以访问其成员变量和方法(只有 public 和 internal)。也就是说 dp_f 可以通过 View 内部的 context 属性来访问其 Context 引用。现在我们不需要将 Context 作为参数传入了,因为它隐含在 View 中。

第二,在导入了 (import) 这些扩展方法的代码段中可以像调用一个对象的普通方法一样调用其扩展方法。在这里,在 v 方法的 lambda with receiver 代码块中可以通过 receiver View 对象直接调用这些方法,像这样:maxWidth = dp_i(120),Kotlin 会识别出需要调用 View 类型的 receiver 对象的 dp_i 方法。

值得注意的一点是,Kotlin 在声明扩展方法时,不会修改其 class。所以在这里,View 类的其他方法不能访问扩展方法,因为扩展方法不是真正意义上的成员。

现在我们就有将 dp 转成 px 的简便方法了。

扩展方法还有其他的用处。现在我们已经看到通过扩展方法可以简化一些棘手的代码,我们利用这一点继续简化 v 方法。

现在我们有两个 v 方法,第一个用于构建根元素,接收 Context,第二个用于创建嵌套于父 View 中的子 View。

inline fun v(context: Context, init: TV.() -> Unit) : TV
inline fun v(parent: ViewGroup, init: TV.() -> Unit) : TV

如果我们不需要传入 Context 或是 ViewGroup 作为参数,岂不是很好?通过扩展方法,我们就像刚才避免将 Context 传入 dp_f 一样重构这段代码。下面使用扩展方法重新实现两个 v 方法,注释是两个方法原本的声明。

你可以看到我们去掉了两个方法的第一个参数(Context 和 ViewGroup),并通过所继承的类来获取所需实例的引用。现在这两个方法都只有一个参数:用于修改 View 的 lambda with recceiver。

修改了方法后,如果我们在 Activity(Context 子类)中写代码,那就可以将 v 添加做 Activity 对象的成员。这样我们就可以以这样更简单的方式构建嵌套 View。

这里调用 v 方法根本不像是在调用方法,因为我们不需要圆括号。在第一部分中我说过,如果方法的最后一个参数是 lambda,那就可以放在圆括号后,而在这里,只有一个参数,根本就不用写圆括号。

Kotlin 中的扩展方法帮我们在代码中很简明易懂地创建构建 View 层级。不过还是有其他问题需要注意。比如我们想设置 TextView 的左内边距为 16dp。

在这里调用 setPadding() 方法与直接修改属性放在一起真是挺丑的,之所以有这样的情况发生,是因为 setPadding() 方法有多个参数,并不是一个 JavaBean 风格的 Setter 方法。所以,Kotlin 不能为其制定一个虚拟属性。不用怕,我会在后续文章中通过 Kotlin 的另外一个功能来弥补这个问题。


感谢徐川对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-05-02 17:312695

评论

发布
暂无评论
发现更多内容

划重点!2022面试必刷461道大厂架构面试真题汇总+面经+简历模板

Geek_0c76c3

Java 数据库 程序员 架构 面试

easyrecovery2023数据恢复软件功能介绍

茶色酒

EasyRecovery easyrecovery2023

怎样徒手写一个React

helloworld1024fd

JavaScript

首次公开!阿里巴巴最新高并发架构设计实录被我从Github扒下来了

Geek_0c76c3

Java 数据库 开源 程序员 开发

OA是什么意思?

优秀

OA oa办公系统 OA是什么意思

OpenHarmony应用HAP包签名

OpenHarmony开发者

OpenHarmony

KubeEdge 1.12版本发布,稳定性、安全性、可扩展性均带来大幅提升

华为云开发者联盟

云计算 云原生 华为云 kubeedge 企业号十月PK榜

java线下培训哪家比较适合小白学习

小谷哥

Go WEB进阶实战:基于GoFrame搭建的电商前后台API系统

王中阳Go

电商 Go web #go #开源 10月月更

开源浪潮下,Apache APISIX 如何成为全球最活跃 API 网关

API7.ai 技术团队

API网关 APISIX 网关 OpenSergo

两种方式修复谷歌翻译无法使用问题

echeverra

会声会影2023全新功能介绍

茶色酒

会声会影 会声会影2023

Java开发培训机构怎样选择靠谱的

小谷哥

imazing2023免费版iOS管理工具

茶色酒

imazing2023

全新出品!Github总榜排行第七的SpringCloud生态全栈笔记我粉了

Geek_0c76c3

Java 数据库 程序员 架构 面经

MathType2023软件安装word教程

茶色酒

MathType2023

后CNN探索,如何用RNN进行图像分类

华为云开发者联盟

人工智能 华为云 CNN 企业号十月PK榜

线下学习web前端培训可以吗

小谷哥

mmmbsc互助系统开发3M智能合约技术

薇電13242772558

智能合约

手把手教你入门Vue,猴子都能看懂的教程

知心宝贝

JavaScript 云原生 Vue 前端 可视化

优秀!阿里甩出GC面试小册,仅7天Github获赞96.9K

Geek_0c76c3

Java 数据库 程序员 JVM 规划

EasyRecovery2023绿色版下载安装教程分享

茶色酒

EasyRecovery15 easyrecovery2023

Android技术分享| Bugly 应用升级自定义UI

anyRTC开发者

android 音视频 UI 移动开发 Bugly

大数据ELK(二十三):Kibana简介

Lansonli

Kibana 10月月更

CDR2023最新版本有什么新功能?

茶色酒

FL Studio水果软件最新21中文版编曲工具

茶色酒

flstudio FL STUDIO20.9 FL Studio 水果FL Studio

easyrecovery15注册机非常强大的数据恢复软件

茶色酒

EasyRecovery Easyrecovery破解 EasyRecovery15

CleanMyMac X2023苹果电脑必备下载软件

茶色酒

CleanMyMac X

超详细教程:在Blender中打造毛毡风格角色

Renderbus瑞云渲染农场

blender Renderbus瑞云渲染

一文带你理解@RefreshScope注解实现动态刷新原理

JAVA旭阳

Java spring 10月月更

大数据开发培训学习费用多少呢

小谷哥

实战Kotlin@Andorid(二):界面构建与扩展方法_移动_Doug Stevenson_InfoQ精选文章