Kotlin 基础(二)- DSL
所谓 DSL 领域专用语言(Domain Specified Language/ DSL),其基本思想是“求专不求全”,不像通用目的语言那样目标范围涵盖一切软件问题,而是专门针对某一特定问题的计算机语言。
Kotlin DSL 定义:使用 Kotlin 语言开发的,解决特定领域问题,具备独特代码结构的 API 。
一、DSL
DSL(domain specific language),即领域专用语言:专门解决某一特定问题的计算机语言,比如大家耳熟能详的 SQL 和正则表达式。使用DSL的编程风格,可以让程序更加简单干净、直观简洁。当然,我们也可以创建自己的 DSL。相对于传统的 API, DSL 更加富有表现力、更符合人类语言习惯。
如果为解决某一特定领域问题就创建一套独立的语言,开发成本和学习成本都很高,因此便有了内部 DSL 的概念。所谓内部 DSL,便是使用通用编程语言来构建 DSL,比如,Kotlin DSL。
1.1 常见的 DSL
常见的 DSL 在很多领域都能看到,例如:
- 软件构建领域 Ant
- UI 设计师 HTML
- 硬件设计师 VHDL
1.2 通用编程语言 vs DSL
通用编程语言(如 Java、Kotlin、Android等),往往提供了全面的库来帮助开发者开发完整的应用程序,而 DSL 只专注于某个领域,比如 SQL 仅支持数据库的相关处理,而正则表达式只用来检索和替换文本,我们无法用 SQL 或者正则表达式来开发一个完整的应用。
- DSL 供非程序员使用,供领域专家使用;
- DSL 有更高级的抽象,不涉及类似数据结构的细节;
- DSL 表现力有限,其只能描述该领域的模型,而通用编程语言能够描述任意的模型;
无论是通用编程语言,还是领域专用语言,最终都是要通过 API 的形式向开发者呈现。良好的、优雅的、整洁的、一致的 API 风格是每个优秀开发者的追求,而 DSL 往往具备独特的代码结构和一致的代码风格。
二、Kotlin DSL 在 Android 开发的应用
2.1 Anko
Anko 是一个 DSL (Domain-Specific Language), 它是 JetBrains 出品的,用 Kotlin 开发的安卓框架。它主要的目的是用来替代以前 XML 的方式来使用代码生成 UI 布局。
2.1.1 使用
Anko 中, 不需要继承其他奇怪的类,只要标准的 Activity, Fragment,FragmentActivity 或者其他任意的类
首先, 在使用 Anko 的 DSL 的类中导入 org.jetbrains.anko.* .
DSL 可以在 onCreate()中使用:
override fun onCreate(savedInstanceState: Bundle?) { super<Activity>.onCreate(savedInstanceState) verticalLayout { padding = dip(30) editText { hint = "Name" textSize = 24f } editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f } } }
不需要显示的调用 setContentView(R.layout.something), Anko 自动为 Activity(只会对Activity)进行 set content view
padding, hint 和 textSize 是 扩展属性. 大多数 View 具有这些属性,允许使用 text = “Some text” 代替 setText(“Some text”).
verticalLayout (一个竖直方向的 LinearLayout), editText 和 button
扩展函数. 这些函数存在与ANdroid 框架中的大部View中, Activities, Fragments ( android.support 包中的) 甚至 Context同样适用.
如果有一个 Context 实例, 可以写出下面的DSL结构:
val name = with(myContext) { editText { hint = "Name" } }
变量 name 成为了 EditText类型.
2.1.2 Helper 方法
你可能注意到了,前面 button 方法接了一个字符串参数,这样的Helper方法同样使用与 TextView, EditText, Button , ImageView.
如果你不需要 View 其他的属性,你可以省略 {} 直接写 button(“Ok”) 或只有 button():
verticalLayout { button("Ok") button("Cancel") }
2.1.3 Layouts 和 LayoutParams
在父布局中布局控件可能需要使用 LayoutParams.xml 中长这样:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android_layout_marginLeft="5dip" android_layout_marginTop="10dip" android:src="@drawable/something" />
Anko 中, 在 View 的后面使用 lparams 来实现类似与 xml 的 LayoutParams。
linearLayout { button("Login") { textSize = 26f }.lparams(width = wrapContent) { horizontalMargin = dip(5) topMargin = dip(10) } }
如果指定了 lparams,但是没有指定 width 或者 height, 默认是 WRAP_CONTENT,但是你可以自己通过使用 named arguments指定.
注意下面一些方便的属性:
- horizontalMargin 同时设置 left 和 right margins
- verticalMargin 同时设置 top 和 bottom
- margin 同时设置4个方向的 margins
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="match_parent" android:layout_width="match_parent"> <EditText android:id="@+id/todo_title" android:layout_width="match_parent" android:layout_heigh="wrap_content" android:hint="@string/title_hint" /> <!-- Cannot directly add an inline click listener as onClick delegates implementation to the activity --> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/add_todo" /> </LinearLayout>
使用 Anko 之后,可以用代码实现布局,并且 button 还绑定了点击事件。
verticalLayout { var title = editText { id = R.id.todo_title hintResource = R.string.title_hint } button { textResource = R.string.add_todo onClick { view -> { // do something here title.text = "Foo" } } } }
可以看到 DSL 的一个主要优点在于,它需要很少的时间即可理解和传达某个领域的详细信息。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) verticalLayout { padding = dip(30) editText { hint = "Name" textSize = 24f } editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f } } }
2.1.4 弹窗
alert("Hi, I'm Roy", "Have you tried turning it off and on again?") { yesButton { toast("Oh…") } noButton {} }.show()
2.1.5 异步
doAsync { // Long background task uiThread { result.text = "Done" } }
关于我
更多信息可以点击关于我 , 非常希望和大家一起交流 , 共同进步
原文地址:https://www.cnblogs.com/1157760522ch/p/11557249.html
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(88)-Excel导入和导出-主从表结构导出
- WCF中的Binding模型之六(完结篇):从绑定元素认识系统预定义绑定
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(57)-插件---ueditor使用
- 何为正则表达式?要他有何用?
- 向silverlight传递自定义参数
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(87)-MVC Excel导入和导出
- sl从程序集中读取xaml文件
- WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇]
- WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇]
- 如何解决打开VS2010后没有UI界面的问题
- RadRails1.0降临——增加Profiler、CallGraph Analyzer和Rails Shell等新特性
- Rails存储库从SVN转向Git
- 报告称10后已变成出境游“老司机”屌丝80后:我还没出过国
- 担心人工智能取代你的工作?听听微软科学家怎么说!
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 剑指Offer LeetCode 面试题39. 数组中出现次数超过一半的数字
- 解决Ajax发送DELETE请求时后台无法接收到参数的问题(Restful风格)
- 解决layui的table数据重载reload where参数会保留上次条件的问题
- 终于弄懂了Layui表格重载数据
- 剑指Offer LeetCode 面试题21. 调整数组顺序使奇数位于偶数前面
- 剑指Offer LeetCode 面试题17. 打印从1到最大的n位数
- 剑指Offer LeetCode 面试题15. 二进制中1的个数
- 剑指Offer LeetCode 面试题11. 旋转数组的最小数字
- 剑指Offer 面试题09. 用两个栈实现队列
- 剑指Offer 面试题06. 从尾到头打印链表
- 剑指Offre 面试题05. 替换空格
- Datatables获取选中行的某一列的数据
- 终于懂了建造者模式
- (力扣)面试题04. 二维数组中的查找
- 一条命令查询电脑多久没关机