用Kotlin和Anko构建UI

    Ankul耆那教徒的
    分享

    自Android开发之初,UI就一直是XML的东西。虽然从理论上讲,UI可以使用Java编程,但它并没有多大用处。不久前,JetBrains引入了Kotlin,这是一种针对JVM的现代语言,可以用于Android。

    Jetbrains宣布Anko是一种更快更简单的Android开发风格。Kotlin提供了库作为DSL(领域特定语言)来设计Android屏幕。举个简单的例子:

    下面是一个简单的Android UI,由imageView和一个按钮

    下面是它的Anko代码:

    verticalLayout {imageView (R.drawable.anko_logo)。lparams(width= matchParent) {padding = dip(20) margin = dip(15)} button("点赞"){onClick {toast("谢谢你的爱!")}}}

    在这里,我们定义了一个垂直线性布局,它作为容器图像按钮.视图在布局中的位置已经使用lparams ().并且,由于Kotlin内联函数,单击按钮时发生的事情也在UI定义中定义。

    使用Anko的优点

    • 我们可以在源代码中嵌入UI布局,从而使其类型安全。
    • 由于我们不是用XML编写,因此不需要在解析XML时浪费CPU时间,从而提高了效率。
    • 在对UI进行编程转换后,我们可以将Anko DSL片段放入函数中。从而促进代码重用。
    • 显然,代码更加简洁、易读、易理解。

    现在,让我们构建一个使用Anko Layout和Kotlin列出任务的待办事项应用程序。

    您可以在上找到此待办事项应用程序的存储库GitHub

    添加Anko库到Android Studio

    看一看用Kotlin简化Android Java代码学习如何将Kotlin添加到您的Android项目。除了Kotlin,我们还需要添加Anko依赖项app / build.gradle这样我们就可以编译这个项目:

    编译'org.jetbrains.anko:anko-sdk15:0.8.3' //sdk19, 21和23也可用

    可以基于此添加此依赖项minSdkVersion您的应用程序的目标。上面的例子描述了它的目标是15 <=minSdkVersion< 19。您可以在Anko 's上查看其他可用的Anko库GitHub存储库。
    我们还将使用以下库:

    编译'org.jetbrains.anko:anko-appcompat-v7:0.8.3'

    在活动中调用Anko布局

    我们不再编写XML布局,因此不需要调用XML视图,也不需要使用XML视图findViewById ()方法。假设我们的Anko UI类是MainUI,然后我们可以在MainUI中设置我们活动的内容为:

    var ui = MainUI() //MainUI类替换XML布局ui. setcontentview (this) //这是指Activity类

    现在创建一个新的Kotlin文件MainActivity.kt并添加以下代码:

    进口android.os.Bundle;进口android.support.v7.app.AppCompatActivity;进口org.jetbrains.anko。*;进口java.util。* class MainActivity: AppCompatActivity() {val task_list = ArrayList() //由任务组成的列表覆盖fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) savedInstanceState?let {val arrayList = savedinstanceate .get("ToDoList")添加All(arrayList as List) } var adapter=TodoAdapter(task_list) //define adapter var ui = MainUI(adapter) //define Anko UI Layout to be used ui.setContentView(this) //Set Anko UI to this Activity } override fun onSaveInstanceState(outState: Bundle?) { outState?.putStringArrayList("ToDoList", task_list) super.onSaveInstanceState(outState) } }

    task_listArrayList它将填充TodoAdapterListview在我们的待办事项应用中。MainUI(适配器)我们的Anko UI文件需要一个适配器TodoAdapter类作为参数。我们来创建TodoAdapter类下。

    构建ListView适配器

    TodoAdapter类有一个成员字段列表类型的ArrayList <字符串>并将BaseAdapter.因此,我们需要重写以下4个成员函数:

    public int getCount() public Object getItem(int i) public long getItemId(int i) public View getView(int i, View View, ViewGroup ViewGroup)

    getView ()我们将使用Anko设计一个列表项的布局。

    重写fun getView(i: Int, v: View?,parent : ViewGroup?) : View { return with(parent!!.context) { //taskNum will serve as the S.No. of the list starting from 1 var taskNum: Int = i +1 //Layout for a list view item linearLayout { lparams(width = matchParent, height = wrapContent) padding = dip(10) orientation = HORIZONTAL //Task Number textView { id = R.id.taskNum text=""+taskNum textSize = 16f typeface = Typeface.MONOSPACE padding =dip(5) } //Task Name textView { id = R.id.taskName text=list.get(i) textSize = 16f typeface = DEFAULT_BOLD padding =dip(5) } } } }
    • 在这个函数中,我们返回一个包含List项的视图horizontalListView布局。这是使用Kotlin 's完成的语法,它允许我们一次对一个对象实例调用多个方法。
    • 每个列表项包含两个textview用于显示任务编号和任务名称。
    • linearLayouttextView是扩展函数。扩展使我们能够启用任何具有新功能的类。
    • 文本textSize字体中定义了它们的getter和setter方法吗android.widget.TextView类。填充是在Anko中定义的扩展属性。

    接下来,我们需要为列表定义操作函数。那么,我们有添加(字符串)删除(Int)的函数TodoAdapter类。添加(字符串)接受要添加的任务名称作为参数。项的位置作为参数删除(Int)函数如下所示:

    //函数添加一个项目到列表有趣的add(文本:字符串){list.add(列表。//从列表中删除一个条目的函数fun delete(i:Int) {list. removeat (i) notifyDataSetChanged() //刷新底层数据集}

    那么,现在我们已经设计了列表,我们也可以向列表中添加和删除项目。这就完成了这个适配器类的代码:

    import android.graphics.Typeface。DEFAULT_BOLD import android.view.View import android.view.ViewGroup import android.widget.BaseAdapter import android.widget.LinearLayout.HORIZONTAL import org.jetbrains.anko。*导入java.util。* class TodoAdapter(val list: ArrayList = ArrayList()): BaseAdapter() {override fun getView(i: Int, v: View?, parent: ViewGroup?): View{返回(parent!!.context) {//taskNum将作为S.No。var taskNum: Int = i +1 //列表视图项的布局linearLayout {id = r.d d. listitemcontainer lparams(width = matchParent, height = wrapContent) padding = dip(10) orientation = HORIZONTAL textView {id = r.d d.taskNum text=""+taskNum textSize = 16f typeface = typeface。MONOSPACE padding =dip(5)} textView {id = R.id.taskName text=list.get(i) textSize = 16f字体= DEFAULT_BOLD padding =dip(5)}}}} override fun getItem(位置:Int):字符串{返回列表[位置]}override fun getCount(): Int{返回列表。size} override fun getItemId(position: Int): Long{//可用于返回表中项目的ID列return 0L} //函数将项目添加到列表fun add(text: String) {list.add(list. add(list. add))size, text) notifyDataSetChanged()} //函数从列表中删除一个项fun delete(i:Int) {list. removeat (i) notifyDataSetChanged()}}

    注意,我们必须导入org.jetbrains.anko。*在我们的类文件中使用Anko DSL。

    设计待办事项界面

    Anko为我们在单独的Kotlin类中拥有活动的UI提供了便利。因此,每个屏幕都可以看作是Kotlin类的一个UI-Activity对。类的功能进行了扩展,从而开发了这个UI类AnkoComponent < T >接口定义在org.jetbrains.anko包中。除了这个接口,JetBrains还提供了一个DSL布局预览免费功能。这是如何Anko DSL布局预览看起来像在Android工作室:

    (来源:blog.必威滚jetbrains.com)
    DSL布局预览

    Anko预览的相应插件可以从在这里.请注意,在撰写本文时,针对Android Studio 2.2的Anko DSL预览被列为开放问题
    回到to -do- app,我们现在将设计MainUI类,它承载所有任务的列表。MainUI类扩展接口。AnkoComponent < T >,在那里T指的是UI的所有者,即活动的内容将是这个UI。在我们的例子中,所有者是MainActivity我们在上面已经定义过了。接下来,在初始化时,必须传递TodAadapter对象添加到该类,因为此适配器将用于填充列表。所以,MainUI类声明变成:

    class MainUI(val todoAdapter: todoAdapter): AnkoComponent

    现在,我们需要重写这个函数createView ()这需要AnkoContext对象作为参数,并返回视图类型:

    重写fun createView(ui: AnkoContext): View = with(ui) {}

    类中提供的UI定义createView ()函数返回给所有者活动,在本例中为MainActivity.那么,让我们开始编码createView ()方法。

    Step1-设计主屏幕

    工作回家
    最初,主屏幕上有一个空的任务列表。我们有一个textView要求用户创建一天的待办事项列表:

    return relativeLayout{//声明ListView var todoList: ListView?=null //没有任务时显示的textView val hintListView = textView("What's your Todo List for today?") {textSize = 20f}。lparams {centerInParent()}}

    centerInParent ()是用于将视图的布局定义为垂直和水平相对居中的辅助方法。
    因为它是一个待办事项应用程序,它的本质在于一个显示任务的列表。这里我们定义列表视图

    //listView verticalLayout {todoList=listView {//assign adapter adapter = todoAdapter}}。Lparams {margin = dip(5)}

    todoAdapter成员变量是MainUI我们在类声明中定义的类。我们发起适配器列表视图价值是todoAdapter这是一个TodoAdpater类对象,并将填充列表。
    为了帮助用户添加任务,我们提供了一个floatingActionButton在主屏幕的右下方材料设计的原则。在Anko中,我们编程floatingActionButton为:

    floatingActionButton {imageResource = android.R.drawable。ic_input_add}。lparams{//屏幕右下角的设置按钮margin = dip(10) alignParentBottom() alignParentEnd() alignParentRight() gravity =重力。底部或重力。结束}
    Step2-显示AddTask警报对话框

    Anko提供了一种简单的设置方式onClickListener视图.所以我们可以加上anonClickListenerfloatingActionButton通过添加onClick ()方法。让我们创建一个自定义对话框出现在点击floatingActionButton,将要求用户输入任务并将其添加到列表中:

    floatingActionButton {imageResource = android.R.drawable。ic_input_add onClick {val适配器= todoList?。适配器as TodoAdapter alert { customView { verticalLayout { //Dialog Title toolbar { id = R.id.dialog_toolbar lparams(width = matchParent, height = wrapContent) backgroundColor = ContextCompat.getColor(ctx, R.color.colorAccent) title = "What's your next milestone?" setTitleTextColor(ContextCompat.getColor(ctx, android.R.color.white)) } val task = editText { hint = "To do task " padding = dip(20) } positiveButton("Add") { if(task.text.toString().isEmpty()) { toast("Oops!! Your task says nothing!") } else { adapter.add(task.text.toString()) showHideHintListView(todoList!!) } } } } }.show() } }.lparams { //setting button to bottom right of the screen margin = dip(10) alignParentBottom() alignParentEnd() alignParentRight() gravity = Gravity.BOTTOM or Gravity.END }
    • 警报{}是创建Anko对话框的内联函数。默认情况下,在Anko对话框中,我们可以设置一个文本消息并提供一个postiveButtonnegativeButton.我们可以使用自定义警报对话框customView
    • verticalLayout是一个linearLayout方向为垂直。
    • 我们已经将标题添加到对话框中工具栏,从而定制它。注意我们如何在对话框中为视图分配颜色:backgroundColor = ContextCompat。R.color.colorAccent色鬼(ctx)
      在这里ctx是指上下文定义在AlertDialogBuilder类。org.jetbrains.anko,我们需要传递一个参数,以便让Android知道我们引用的上下文。
    • postiveButton ()是一个Anko Helper方法,它允许我们定义当用户提交对话框时会发生什么。这里我们在检查是否任务不为空,则我们正在使用添加中定义的方法TodoAdapter类。
    • 是什么showHideHintListView(基于! !)?这是我们定义的隐藏textView的方法hintListView它出现在主屏幕上,以便为我们的列表腾出空间。当listView为空时,我们显示hintListView否则我们就把它藏起来。

      //函数显示或隐藏在textView上面
      showHideHintListView(listView: listView) {
      if (getTotalListItems(listView)>0) {
      hintListView。能见度=视图。走了
      }其他{
      hintListView。能见度=视图。可见

    在这里,getTotalListItems(视图)的成员方法是MainUI类,该类返回项的个数的计数列表视图过去了。它是一个普通的Kotlin函数:

    //函数获取列表中条目的总数getTotalListItems(list: ListView?) = list?.adapter?。计数?:0

    最后点击floatingActionButton我们看这个对话:

    添加任务

    一旦我们添加了一些任务,我们可以看到任务列表:

    任务列表

    步骤3-删除任务

    记住,我们已经定义了删除(Int)方法TodoAdapter从列表中删除项的类。现在是时候设计UI来调用它了
    方法。遵循Android设计模式,我们可以在轻按并按住任务时显示任务选项。我们来定义一下发生了什么onLongClick列表项的。回到列表视图定义并添加以下内容:

    onItemLongClick {adapterView, view, i, l -> val options = listOf("Delete") selector("Task options ", options) {j -> var Task =adapter.getItem(i) todoAdapter?.delete(i) //检查是否列表为空,然后显示提示showHideHintListView(this@listView) longToast("Task ${Task}已被删除")}true}
    • 在这里todoAdapter的对象TodoAdapter类。调用删除方法适配器给出一个错误,表示它可能在时间之前已经更改。所以,我们必须打电话删除方法todoAdapter.另一种选择是类型转换适配器TodoAdapter.kotlin的做法是:
      ?.delete(i)
      指向正在被单击的项目位置。
    • 选择器是一种安科对话框这给了我们定义可点击项列表的选项。这里我们只采取了一个选项,即删除。我们可以为用户提供其他选择。下面是一个例子:
    verticalLayout{基于网络适配器= = listView {todoAdapter onItemLongClick {adapterView,看来,我,l - > val选项=自然(“完成”、“进步”,“没有开始”,“删除”)选择器(“任务”选项,选项){j - >如果(j = = 3) {var = adapter.getItem任务(我)todoAdapter ? Delete (i) showHideHintListView (this@listView) longToast(“任务${任务}已被删除”)}其他{longToast(“任务$ {adapter.getItem (i) .toString()}已标记为\“$ {[j选项 ]}\"") } } 真正的}}}。Lparams {margin = dip(5)}

    数据库更新、通知用户或任何其他代码都可以代替toast来增强待办事项应用程序的功能选择杆对话框在屏幕上是这样的:

    任务的选择

    因此,完整的代码MainUI类:

    进口android.support.v4.content。上下文Compat import android.view.Gravity import android.view.View import android.widget.FrameLayout import android.widget.ListView import org.jetbrains.anko.* import org.jetbrains.anko.appcompat.v7.toolbar import org.jetbrains.anko.design.floatingActionButton class MainUI(val todoAdapter: TodoAdapter) : AnkoComponent { override fun createView(ui: AnkoContext): View = with(ui) { return relativeLayout { var todoList : ListView? =null //textView displayed when there is no task val hintListView = textView("What's your Todo List for today?") { textSize = 20f }.lparams { centerInParent() } //function to show or hide above textView fun showHideHintListView(listView: ListView) { if (getTotalListItems(listView)>0) { hintListView.visibility = View.GONE } else { hintListView.visibility = View.VISIBLE } } //layout to display ListView verticalLayout { todoList=listView { adapter = todoAdapter onItemLongClick { adapterView, view, i, l -> val options = listOf("Completed","In Progress","Not Started","Delete") selector("Task Options", options) { j -> if (j == 3) { var task=adapter.getItem(i) todoAdapter?.delete(i) showHideHintListView(this@listView) longToast("Task ${task} has been deleted") }else{ longToast("Task ${adapter.getItem(i).toString()} has been marked as \"${options[j]}\"") } } true } } }.lparams { margin = dip(5) } //Add task FloatingActionButton at bottom right floatingActionButton { imageResource = android.R.drawable.ic_input_add onClick { val adapter = todoList?.adapter as TodoAdapter alert { customView { verticalLayout { toolbar { id = R.id.dialog_toolbar lparams(width = matchParent, height = wrapContent) backgroundColor = ContextCompat.getColor(ctx, R.color.colorAccent) title = "What's your next milestone?" setTitleTextColor(ContextCompat.getColor(ctx, android.R.color.white)) } val task = editText { hint = "To do task " padding = dip(20) } positiveButton("Add") { if(task.text.toString().isEmpty()) { toast("Oops!! Your task says nothing!") } else { adapter.add(task.text.toString()) showHideHintListView(todoList!!) } } } } }.show() } }.lparams { //setting button to bottom right of the screen margin = dip(10) alignParentBottom() alignParentEnd() alignParentRight() gravity = Gravity.BOTTOM or Gravity.END } }.apply { layoutParams = FrameLayout.LayoutParams(matchParent, matchParent) .apply { leftMargin = dip(5) rightMargin = dip(5) } } } //function to get total number of items in list fun getTotalListItems(list: ListView?) = list?.adapter?.count ?: 0 }

    最终的想法

    在开发这个待办事项应用程序时,我们没有使用任何XML布局资源,但我们能够以类似的风格设计应用程序。Anko消除了显示数据的负担,响应用户交互,连接到数据库,以及更多,从一个应用程序中的活动或片段。此外,隔离UI和活动类使应用程序更接近MVP (Model-View-Presenter)体系结构。您可以从以下网站了解Anko的高级功能在这里
    虽然它有一些缺点,如编译速度较慢和应用程序大小较大,但在重用、维护和测试代码方面,它具有很强的影响力。因此,Kotlin-Anko完全适用于Android产品应用。

    请在评论区告诉我你对Anko的看法。

    Baidu