/写在前面

翻开自己的CSDN,已经很久很久没有活动了,最近的关于PDF签章的博客还是16年写的。将近年关,工作内容阶段性告一段落,终于有时间写一下自己的东西。

废话少说,说说Kotlin。kotlin开发者给kotlin的定位---不是用来取代任何一种语言,而是 让开发者有更多的选择,更加便捷的开发自己的产品。kotlin不是学院派语言,而是工程性质的语言,kotlin并没有带给开发者更多的新奇的技术,而是把工程实践中,开发者觉得很便捷的技术特性 集成到kotlin中。

最初没有真正在项目中用到kotlin之前,我同大部分人的看法是一致的,以为kotlin无非是java的升级,语法糖而已。后来,抱着学习语言特性的想法,学习了kotlin,并用到自己项目中之后,才发现kotlin的真正牛掰之处。基于kotlin与java的无缝互操作,到目前为止,我已经很少写java代码了。

下边,开始kotlin + DSL(Anko),给大家开发时一个新思路

给大家介绍一下kotlin + anko的强大之处,文章比较长,希望对各位开发同学有所帮助

有所谓 仁者见仁智者见智,kotlin + anko还处于成长中,不一定适合所有开发环境。

我的建议是,可以在项目中 将xml和anko结合起来。 xml和anko各有优势,并且anko可以用include包含xml,anko的优势是 动态生成和复用。 二者结合,相信可以更加便捷的开发。

本文所用的源码demo,在码云上开源,地址如下

https://gitee.com/akai_liu/AkaiKotlinWithAnko

推荐几个地址,本文不说kotlin语法基础和如何构建项目,需要这方面的可以参考如下

kotlin极简教程

kotlin官方文档中文版

《Kotlin for android developers》中文版翻译

anko github

kotlin协程github

开始

准备工作

打开android studio,新建kotlin项目,在项目gradle中配置如下版本号 
在app gradle中配置如下依赖, 协程 和 anko 可以依据自己需要的模块添加,具体可参考上述官方github
kotlin协程是异步处理事件,比如网络请求等,是kotlin比java增加的新特性,可以像写同步代码一样写异步调用代码,熟悉C#和scala等语言的 对于协程应该都很熟悉了。对于本文的demo,没有用到协程。
后续如有机会,会单独把协程写一个博客。
接下来,就可以用kotlin+DSL进行开发了。

Anko开始

1、万里之行,始于hello world

熟悉的步骤,新建MainActivity类,不需要创建 xml布局文件,也不需要setContentView
接下来,直接在activity onCreate中写hello world
OK了,就这么简单, 一个framelayout 布局, 内嵌一个textView ,好了,如果现在运行到模拟器上,看到的样子应该是

2、Anko布局与Activity分离

anko基本实现方式

看了上边的代码,是不是觉得有些疑惑,这是如何实现的呢? 让我们在开始下一步介绍之前,先来看看framelayout和textView这两个标签的kotlin源码。
其实,Kotlin官方帮我们构建了一个名为Anko的UI库,基于Kotlin带接收者的lambda表达式实现的。
以framelayout为例,framelayout标签 其实是anko定义的内联函数,熟悉kotlin的同学可以看出来,函数返回值就是android的framelayout。函数 入参init 是个带接收者的lambda表达式,用来设置framelayout的属性。
看到这里,大家应该明白了吧,说白了,其实就是新建framelayout类对象,再给framelayout对象设置属性。基于kotlin的语法特性,看起来就像是 一个名叫framelayout的脚本标签。(其实gradle配置文件也是如此,也是基于DSL(特定领域语言)实现的,只不过一般不去关注具体实现细节了)
OK了,大家应该稍微明白写了,为什么 能再 activity onCreate中直接使用 framelayout,因为framelayout实际上是Activity的一个扩展函数,又framelayout函数的入参 只有一个 带接收者的lambda表达式,根据kotlin的约定,函数调用时括号可以省略,最后一个lambda表达式可以写在括号外边,所以就变成了 framelayout{ } 这种形式。
其实,anko不止为Activity定义了各个ui控件的扩展函数,也为其他例如 viewManager等类都定了扩展函数,基于此,我们可以将UI布局 不写到Activity里,以免activity中UI代码过多,不便于管理。
我们基于上边说的anko封装原理,可以将 UI代码写到别的类中,然后在activity或fragment中调用。
anko为了方便开发者写出统一方便的代码,专门提供了一个封装ui用的接口AnkoComponent,函数有个泛型T,用来指定是哪个activity/fragment的ui(当然也可以是BaseActivity或BaseFragment)。AnkoComponent有个抽象函数,createView,用来生成布局。
下边我们将 刚开始写的hello world修改一下,把framelayout和textview 从activity中分离出来。

使用AnkoComponent接口

新建类MainActivityUI 实现 AnkoComponent接口
如图,继承后重写createView函数,函数返回 View就是布局的view, 入参ui 可以理解为对 MainActivity的封装,里边有owner(MainActivity的实例),ctx(对应的context)等属性。
为了方便调用入参ui,我们将函数的实现写法稍微修改一下,使用ui.apply{}表达式,如下
这样,我们就可以在apply表达式中 类似写 xml布局的形式,写 anko布局了。如下,但是,这里使用的 framelayout函数,并不是 activity的扩展,而是viewManager的扩展,可以点开源码看到定义。不过,这对于使用者来说,并没有什么差异。
接下来,就需要把UI 绑定到 对应的activity中,与 xml形式layout 类似,我们这样在oncreate中写
在fragment中,类似的这样
OK,搞定, 运行到 模拟器中,同样会看到刚开始的 hello world界面。
顺便说一下,如果你的android studio安装的有anko support插件的话,继承自AnkoComponent的类,是可以像xml一样预览效果的(不过这个插件目前还不是很强大,每次预览,都需要build一下porject)

3、稍微进阶,UI布局中插入代码

各位看到这里,估计心里会有嘀咕,这不是和写xml布局文件一样么,看不出来有什么差别。甚至连预览都那么麻烦。OK,这只是表面现象,下边,我们开始一步一步的揭示,anko的强大。

根据大家的经验,xml文件中只能写静态页面,如果有动态需求,就需要用java类动态生成,且不说java类写界面有多繁琐,单是与xml的交互,就没那么容易。

但是,这些事情,对于kotlin/Anko来说,易如反掌,天生支持。

上文说过,虽然anko写UI看起来类似xml中使用view标签,但是anko中其实每个‘标签’本质都是一个扩展函数,因此,在函数中写代码,绑定事件,动态生成布局,这是再正常不过的事情了,特别是anko为开发者封装了很多方便的工具。

基于上述的hello world项目,我们先来个简单的修改,给hello world绑定一个点击事件,土司一句话。如下截图

是不是很简单,这时,运行到模拟器上,textView就会有onclick事件了,弹出一个提示“我是hello world”。

同样,可以在textView 之后 直接用常规的  .setOnClicklistioner调用,不过,那样不么是显得啰嗦么。

onClick函数和 toast函数是 anko封装的扩展函数,就是为了减少开发时不必要的样板代码。

有了这个操作, 对于只执行简单操作的按钮 等控件view,点击事件 就可以顺手写在ui里。 比如只是为了跳转页面,直接在onclick中写 startActivity就好了,省去了定义id findview等很多麻烦。

4、在activity中,使用view

看了上边的介绍,大家一定有这样的疑问,我们总不能把所有的代码都写到 UI类中吧,那样太傻了。

OK,下边就看看我们怎样在activity中操作view。

先在activity中定义view,然后在AnkoComponent中实例化view,最后,activity中就可以使用view了。

上文说过,AnkoComponent重写的函数createView 的入参ui ,包含了绑定的activity/fragment的实例,基于此,我们可以如下实现

类似如下过程,

为了不进行多余的 kotlin空指针处理,这里把textView定义为懒初始化属性。

然后在AnkoComponent中实例化,最后,就可以在 绑定ui之后 使用textView了。

这样,是不是省去了大量findView操作呢?

当然,我们同样可以 在UI中指定View的Id属性,在activity中使用findView的方式来实例化。然而,我们多数时候不会这样做,因为findViewbyId是比较消耗的操作,可以直接代码实例化的话,还是尽量不用findView。

配置View的id,不一定是为了findview才配置的。还有一个作用是在activity中区分不同的view,比如在activity中统一处理点击事件。

5、再次进阶,使用自定义view

anko为我们封装好了 android原生包括support库design库用到的所有控件,能够完成我们大部分的工作。但是,很多时候我们需要自定义控件,那么,我们怎么在anko中使用自定义控件呢?

上文,有介绍framelayout源码的定义,其实,我们按照源码,就可以定义自己的anko控件了。

比如,我从网上找了一个 圆形imageview的自定义控件RoundImageView(java也好,kotlin也好,都不影响,因为kotlin与java无缝互操作),代码太长我就不贴了,可以到项目中查看。

那么,我需要怎样配置,才能在anko中使用呢?

为了方便,我单独为自定义view建一个配置用的kotlin file,叫ConfigMyView, 并仿照anko源码,定义RoundImageView的内联函数,如下截图,由于我是在AnkoComponent中使用这个函数,所以我只声明了ViewManager的扩展函数。

OK,有了这个定义后,我们就可以使用roundImageView标签了。我们稍微修改一下hello world项目,把自定义的view加进入,把原来hello world删除掉,把跟布局改为relativeLayout。先从网上下载一张png图片

然后,放到roundImageView里,看看是什么效果

好了,这样,自定义view也可以用了。

6、重点来了,复用 复杂布局,不仅仅是 复用布局。

至此,我们基本可以正常使用akno进行开发了,但是,各位看官,是不是依旧没有看出anko的优势在哪里?别急,如下,就是见证奇迹的时刻。

根据经验,很多时候,同一个项目中,同一个布局样式会在很多处都出现,为了使用方便,我们会单独为这些布局写一个xml文件,然后在不同的地方使用include 的方式引用。 anko同样支持include操作引用xml文件,来实现xml与anko的交互。

但是,anko能做的不仅仅是这样。

我们来设定一个需求,做一个类似如下形式的输入框。 输入框背景可自定义,输入框头部图标可自定义,输入框提示文字可自定义,输入框会判断输入内容正确性,正确显示对号,错误显示红叉,输入时 显示灰色叉子,点击灰色叉子可以删除输入框内容。

然后,在项目中,这种类型的输入框,有好多个,那么怎么办?

我们想想这个要怎么实现,如果使用传统的xml方式, 我们可以单独写一个输入框布局,然后在每次include后,在activity中一个一个findview,然后设置对应控件的属性,例如头部图标图片,对号叉子图片,输入框提示内容,并且要指定输入框各个事件,让对号红叉可以正常显示 等等等。

上述过程,光想想都够酸爽,如果 项目中多处用到,呵呵。。。

当然,如果您是大拿,说直接自定义view实现,那我拜服。

ok,来看看使用kotlin anko可以怎样实现?

①准备资源
背景可以是图片或者 drawable xml文件,为了方便,我就不用图片了,我写一个drawable xml,如下
准备输入框头部的图标,我下载个手机的图标,起名叫做phone.png

然后再下载3个图标 对号 ,红叉子,灰色叉子 作为 输入框尾部的图标

② anko书写布局,并绑定事件
准备好资源,我们下边新建一个类,普通类MyInputEdit,成员变量如下,这个可以自己根据需要增加或减少,有几个成员变量我们给了默认值,因为这几个不需要经常变化。
另外,为了后续方便 单独设置某个控件的属性,我们再增加几个成员变量,总体如下

下边,我们根据需求,分析对应的输入框布局。

最外层linearlayout水平布局,头部放一个imageview,中间放个edittext,尾部 framelayout 中放3个imageview,OK,其实布局结构很简单,我们在MyInputEdit中添加一个函数getInputEdit(),用来生成这样的布局,入参viewManager。

接下来,就是分析事件绑定了,我们简单的实现一下。

1、edittext失去焦点时,判断 输入正确 错误,如果没有输入,则什么都不显示

2、在文本编辑时,显示 灰色叉子,一键清空输入内容

因此,edit需要绑定 onFocusChangeListener 和 textChangedListener

尾部删除imageView需要绑定点击事件

为了方便控制 尾部3个imageview的显示,我们增加一个函数来控制showInputCheckIcon

ok,让我们先来看 edit的onFocusChangeListener中的逻辑

再看看textChangeedListener中的逻辑

删除按钮的点击事件很简单,点击后 清空 edittext就行了

ok,完整的 函数代码,可以到 项目中查看,太长,就不贴了

除此之外,我们再增加一个获取输入内容的函数,方便后续使用

OK,至此,MyInputEdit类基本完成,整体如下

③AnkoComponent UI类中使用MyInputEdit类
在UI类中,使用如下截图,很简单
红框部分,怎么样,代码是不是很简单, 几句代码,就可以满足我们的需求,不仅仅是布局样式,就连各个事件也OK了。

ok,我们再来一个 密码输入框,同样的方式,但因为是密码,我们需要多传一个参数,输入类型

运行后,如下效果

基于此,一般连同 注册页面, 登陆页面, 忘记密码页面,修改密码页面,我们可能需要很多个类似的输入框,使用kotlin anko,可以轻松的把实现 复杂的 输入框需求,并且不需要自定义view。

看到这里,您是不是开始有些明白anko的强大之处了呢?

7、继续进阶,使用函数来定义各种类型的布局复用,不仅仅是布局

我们来看看另外一种,实现布局复用的方式-----直接定义布局函数

第6节中,因为 子布局有很多事件需要处理,所以,我们直接建一个类来方便事件绑定

然而,对于一般没有很多事件处理的 复用布局,我们可以直接定义函数来进行复用。

比如这样的需求,我们项目中可能有 很多类似如下的 动作条 ,有时带有头部图标,优势带有尾部图标

并且有的还可以显示用户内容,用户内容可能是图片或者文字,文字有可能要经过特殊处理(如截图中手机号不完全显示),动作条本身又有点击事件。

我们思考一下,如果用xml layout文件我们要怎么实现?用java动态布局要怎么实现?是不是很酸爽?
当然,如果同一页有多个排列的这样的布局,我们可以用 adapter view展示,比如listview等。
如果每一页只需要一两个这样的布局,但是很多页都需要,那用adapterview就有点 高射炮打苍蝇的感觉了。
ok,我们看看使用 kotlin函数怎么实现
还是那样,先分析需求
1、总体linearlayout + 需要的背景
2、头部图标 ,可以控制是否显示
3、头部文字,可以修改
4、用户信息部分,可以自定义是什么样的view ,可以是文字 或者图片,可以控制是否显示
5、尾部的箭头 可以自定义图标 并控制是否显示

基于此,我们定义一个类似如下的内联函数, 入参根据需求,暂时定如下这几个

由于 显示用户信息的部分,有可能是图片或者 文字,或者其他信息,所以我们给函数定义一个泛型T,View类型, 入参部分预留T的init初始化 lambda表达式。
函数的实现部分,就是 堆布局了,如下
OK,布局函数定义完毕,那么,我们在AnkoComponent中怎么使用呢?很简单,类似MyInputEdit类一样,直接到 UI代码中写就好了。
在 AnkoComponent中 依次添加 需求截图中的,用户头像显示, 用户手机号显示,设置  3个动作条
如下

运行之后的效果如下,还有点击事件

结束语

好了,看到这里,大家估计也明白anko的优势所在了,就是 布局与代码的 嵌套,基于此,我们可以很方便的用简单的方式 复用很多ui代码,动态生成ui等等。
后续有时间的话,还会继续介绍kotlin,强化自己的学习,顺便分享所得。感谢!
再次,android UI可以用xml与anko混合开发,各取所长,相信会带给大家开发的便利。
这一篇就简单介绍到这里,由于我水平有限,文中难免有错误和不足,欢迎指摘,感谢!
-------------------------------------------------------------akai.liu -- 2018-02-08

Kotlin/DSL(Anko),原汁原味Kotlin开发Android---Activity Fragment与AnkoUI分离,强大的复用,更加便捷的开发相关推荐

  1. android 美颜相机开发,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,以及像抖音,唱吧之类带有视频的软件,功能很强大,其实现原理基本上都是 ...

  2. android activity fragment 销毁,activity被销毁而fragment未被销毁视图残留的处理方法

    环境描述:java7+android studio2.2+sdk14 背景描述:目前主流的应用主页一般是一个MainActivity托管几个fragment.我的主页MainActivity继承自Fr ...

  3. Android Activity/Fragment间的数据传递

    Activity间的数据传递 举例:MainActivity是已经打开的Activity,在这个界面打开第二个Activity,SecondActivtiy,如果是直接通过startActivity( ...

  4. 像 Compose 那样写代码 :Kotlin DSL 原理与实战

    1. 前言 Kotlin 是一门对 DSL 友好的语言,它的许多语法特性有助于 DSL 的打造,提升特定场景下代码的可读性和安全性.本文将带你了解 Kotlin DSL 的一般实现步骤,以及如何通过 ...

  5. Kotlin DSL 实战

    1. 前言 Kotlin 是一门对 DSL 友好的语言,它的许多语法特性有助于 DSL 的打造,提升特定场景下代码的可读性和安全性.本文将带你了解 Kotlin DSL 的一般实现步骤,以及如何通过 ...

  6. 使用phoneGap和Sencha Touch 2开发Android应用程序(四)

    2019独角兽企业重金招聘Python工程师标准>>> 本文是" 使用phoneGap和Sencha Touch 2开发Android应用程序"系列教程的第4章, ...

  7. 用HTML5/CSS3/JS开发Android/IOS应用

    现在人人都想成为安卓/IOS应用开发工程师.其实,安卓/IOS应用可以用很多种语言来实现.由于我们前端开发工程师,对HTML5/CSS/JavaScript的网络编程已经相当熟悉了.所以,今天大家将会 ...

  8. 【26】Android - 初识Fragment

    目录 目录 前言 相关库包 简单使用 静态加载 动态添加 Fragment 与Activity 通讯 组件获取 消息传递 生命周期 基本状态 回调 测试 进阶使用 如何在 Fragment 中增加 M ...

  9. 《Kotin 极简教程》第13章 使用 Kotlin 和 Anko 的Android 开发

    第13章 使用 Kotlin 和 Anko 的Android 开发 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: ...

最新文章

  1. Shell脚本经典之Fork炸弹
  2. sublime text3
  3. 网页底部的版权信息_Shopify底部的版权信息(Powered by Shopify )如何删除
  4. 集合添加元素python_Python 集合(Set)
  5. LeetCode 497. 非重叠矩形中的随机点(前缀和+二分查找)
  6. sqlserver的for xml path和mysql的group_concat的区别
  7. Spark算子:RDD键值转换操作(5)–leftOuterJoin、rightOuterJoin、subtractByKey
  8. 跟着百度学PHP[3]-PHP中结构嵌套之循环结构与条件结构嵌套
  9. mac安装win7之后鼠标失灵_苹果电脑安装win7时键盘鼠标无响应3种解决方案
  10. 《软件工程之美》打卡第六周
  11. Java 相关知识的学习(第一章至第三章)
  12. win10系统 Windows 资源保护找到了损坏文件 无法修复的有效解决方法
  13. Win7网络和共享中心 依赖服务或组无法启动 解决办法
  14. 工作组和域的概念及辨析
  15. Scrapy中的item和pipline
  16. php think-queue队列的安装使用和Supervisor的安装配置和使用
  17. 零基础Unreal Engine 4(UE4)图文笔记之准备篇(一)
  18. UE4-蓝图-角色的移动,视角控制(四)人物瞄准偏移(视角自由转动)
  19. 奥克兰大学计算机科学硕士,奥克兰大学计算机硕士解析
  20. 内存、ram、 rom、 norflash,nandflash详细区别

热门文章

  1. opencv warpAffine()函数详解 -- 图像旋转与平移
  2. css firefox火狐浏览器下的兼容性问题
  3. Libuv源码解析 - uv_loop整个初始化模块
  4. 什么是知识图谱(Knowledge Graph)(上)
  5. 基于ndis protocol driver 后门 分析
  6. nvme固态硬盘开机慢_6个固态硬盘优化设置技巧 让你的SSD速度飞起来 (全文)
  7. 大学计算机基础导论备考
  8. 【5G RLC】AM模式的数据传输详解
  9. sqlserver2008 R2数据库-不允许表修改保存,阻止保存要求重新创建表的更改
  10. LaTex支持中文的三种方式