为什么Anko布局?
DSL的原因?
默认情况下,Android中的UI是用XML编写的。这在以下方面是不方便的:
- 不是类型安全;
- 不是空值安全;
- 它迫使您为每一个布局编写几乎相同的代码;
- 在设备上解析XML,浪费CPU时间和电池;
- 最重要的是,它不允许代码重用。
虽然您可以通过编程方式创建UI,但这几乎是不可能完成的,因为它有点难看,很难维护。这是一个普通的Kotlin版本(Java中的一个更长的版本):
1 | val act = this |
DSL使相同的逻辑易于阅读,易于编写,并且没有运行时开销。这里又有了:
1 | verticalLayout { |
注意,onClick()
支持协程(接受suspending lambda),这样您就可以在没有显式的async(UI)
调用的情况下编写异步代码。
支持现有的代码
你不需要重写Anko的所有UI。您可以用Java编写旧的类。此外,如果您仍然希望(或有)编写一个Kotlin activity类,并出于某种原因使XML布局膨胀,您可以使用视图属性,这将使事情变得更简单:
1 | // 与findViewById()相同,但使用起来更简单 |
通过使用Kotlin的Android扩展,您可以使您的代码更加紧凑。
它是如何工作的
没有🎩。Anko由一些Kotlin的扩展函数和属性组成了类型安全的构造器,就像类型安全的构建器所描述的那样。
由于手工编写所有这些扩展有点乏味,所以它们是由Android SDK中的android.jar文件自动生成的。
它是可扩展的吗?
简短的回答:是的。
例如,您可能想要在DSL中使用MapView。然后把它写在任何可以导入的Kotlin文件中:
1 | inline fun ViewManager.mapView() = mapView(theme = 0) {} |
{ MapView(it) }
是您自定义View
的工厂函数。它接受一个Context
实例
现在你可以这样写了:
1 | frameLayout { |
如果你想让你的用户能够应用一个定制的主题,你也可以这样写:
1 | inline fun ViewManager.mapView(theme: Int = 0) = mapView(theme) {} |
在你的项目中使用Anko Layouts
这些库依赖关系包括:
1 | dependencies { |
请阅读基于Gradle的项目部分,以获得详细信息。
理解Anko
基础知识
在Anko,你不需要从任何特殊的类继承:仅仅使用标准的Activity
、Fragment
、FragmentActivity
或任何你想要的东西。
首先,导入org.jetbrains.anko.*。在您的类中使用Anko布局DSL。
在onCreate()
中可以使用DSL:
1 | override fun onCreate(savedInstanceState: Bundle?) { |
🐧 没有明确的调用
setContentView(R.layout.something)
: Anko为Activities
自动设置内容视图(但只对他们)。
hint
和textSize
是与java风格的getter和setter绑定的合成扩展属性,padding
是Anko的扩展属性。这些都存在于几乎所有View属性中,允许您编写text = "Some text"
而不是setText("Some text")
。
verticalLayout
(一个线性布局
,但已经有了LinearLayout.VERTICAL
方向)、editText
和button
是构造新Viwe实例并将它们添加到父类的扩展函数。我们将引用这些函数作为块。
在Android框架中几乎所有的视图都存在块,它们在Activities、Fragments(默认情况下和android.support package)甚至是Context。例如,如果您有一个AnkoContext实例,您可以编写这样的块:
1 | val name: EditText = with(ankoContext) { |
AnkoComponent
尽管您可以直接使用DSL(在onCreate()或其他任何地方),但不需要创建任何额外的类,在单独的类中使用UI通常是很方便的。如果您使用了提供的AnkoComponent接口,那么您还可以免费获得DSL布局预览功能。
1 | class MyActivity : AppCompatActivity() { |
辅助块
正如您可能已经注意到的,前一节中的button()
函数接受一个字符串参数。
对于常用的View,例如TextView
、EditText
、Button
或ImageView
,都存在这样的辅助块。
如果您不需要为某个特定View设置任何属性,您可以省略 {},编写button(“Ok”),甚至只是button():
1 | verticalLayout { |
主题块
Anko提供了“themeable”版本,包括辅助块:
1 | verticalLayout { |
布局和LayoutParams
可以使用LayoutParams
对父容器中的小部件进行定位。在XML中,它是这样的:
1 | <ImageView |
在Anko中,使用lparams()在View描述后,指定了LayoutParams。
1 | linearLayout { |
如果您指定了lparams()
,但是省略了width
和/或height
,它们的默认值都是wrapContent
。但是您总是可以显式地传递它们:使用命名参数。
一些方便的辅助属性可以注意到:
horizontalMargin
设置左和右的边距verticalMargin
设置顶部和底部的边距margin
同时设置了所有四个边距
注意,对于不同的布局,lparams()
是不同的,例如,在相对布局
的情况下:
1 | val ID_OK = 1 |
Listeners
Anko有一名监听器的助手,他们可以无缝地支持协程。您可以在listener内编写异步代码!
1 | button("Login") { |
几乎和这个是一样的:
1 | button.setOnClickListener(object : OnClickListener { |
当你有很多方法的时候,Anko是很有帮助的。考虑下面的代码,没有使用Anko:
1 | seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { |
现在,Anko:
1 | seekBar { |
如果您为相同的View
设置onProgressChanged()
和onStartTrackingTouch()
,那么这两个“部分定义”的listener将被合并。对于相同的listener方法,最后一个获胜。
定制的协程上下文
您可以将一个定制的协程context传递给listener助手:
1 | button("Login") { |
使用资源标识符
前面几章中的所有例子都使用了原始Java字符串,但这并不是一个好的实践。通常,您将所有的字符串数据放入res/values/
目录中,并在运行时调用它,例如getString(R.string.login)
。
幸运的是,在Anko中,您可以将资源标识符传递给助手块(button(R.string.login)
)和扩展属性(button { textResource = R.string.login }
)。
注意,属性名不是相同的: text
、hint
、image
,而是我们现在使用的是textResource
、hintResource
和imageResource
🐧 资源属性读时总是抛出AnkoException。
实例简化符号
有时候,您需要从活动代码中传递一个Context
实例到某个Android SDK方法。
通常,你可以使用this
,但是如果你在一个内部类里面呢?
如果您在Kotlin编写,您可能会在Java和this@SomeActivity用SomeActivity.this。
对Anko,你可以写ctx。它是一个扩展属性,既可以在Activity和Service中工作,也可以从Fragment中访问(它的外壳是使用getActivity()方法)。
您还可以使用act扩展属性获得一个Activity实例。
UI包装
在开始之前,Anko总是使用UI标签作为顶级的DSL元素:
1 | UI { |
如果你想的话,你仍然可以使用这个标签。而且,扩展DSL要容易得多,因为您必须只声明一个ViewManager.customView函数。请参见扩展Anko获取更多信息。
Include标签
可以很容易将XML布局插入到DSL中。
使用include()函数:
1 | include<View>(R.layout.something) { |
您可以像往常一样使用lparams(),如果您提供了一个特定的类型而不是View,您也可以使用这个类型:
1 | include<TextView>(R.layout.textfield) { |
Anko支持插件
Anko支持插件可用于IntelliJ IDEA和Android Studio。它允许你在IDE工具窗口中直接预览与Anko一起编写的AnkoComponent类。
⚠️ Anko支持插件目前只支持Android Studio 2.4+。
安装Anko支持插件
你可以在这里下载Anko的支持插件。
使用插件
假设你用Anko写了这些classes:
1 | class MyActivity : AppCompatActivity() { |
将光标放在MyActivityUI
声明的地方,打开Anko布局预览工具窗口(“View” → “Tool Windows” → “Anko Layout Preview”),并按下刷新。
这需要构建项目,因此在实际显示图像之前需要花费一些时间。
XML DSL转换器
该插件还支持将XML格式的布局转换为Anko布局代码。
打开一个XML文件并选择”Code” → “Convert to Anko Layouts DSL”。
您可以同时转换多个XML布局文件。