Kotlin 结合 Anko 编写布局

什么是Anko?

Anko是由 Android Studio 的开发公司 jetBrains 官方出品的针对Kotlin语言,并且使开发Android程序更高效更简单的库,它可以使代码更简洁优雅。
它可以分为几个部分:

  • Anko Commons: 这个里面包括很多使用的工具,可以帮助我们减少代码量,包括intents ,dialog,log,还有好多....
  • Anko Layouts: 是一种快速,type-safe的动态 Android 布局方案
  • Anko SQLite: 帮助查询SQLite的DSL 解析器集合
  • Anko Coroutines:基于kotlin 协程的扩展工具

为什么要使用Anko来写布局呢?

在常规的Andorid开发中,我们都是用XML写布局,在这几个方面有点不方便:

  • 不是type-safe的;
  • 不是null-safe的;
  • 每个布局文件都要写好多重复的代码
  • 在Android设备上解析XML会更加耗时和耗电
  • 不能重用

而且当我们想用代码直接创建UI的时候,会使代码看起来很难维护,并且不够优雅。

val activity = this
val layout = LinearLayout(act)
layout.orientation = LinearLayout.VERTICAL
val button = Button(act)
button.text = "退出登录"
button.setOnClickListener {
    logout()
}
layout.addView(button)

上面是动态添加一个退出按钮的操作,已经是kotlin中简化的代码了,可以说是又丑可读性也差,如果用java写的话会更长。如果用Anko的DSL方式编写会是什么样呢?


verticalLayout {
    button("退出登录") {
        onClick { logout() }
    }
}

一个普通的设置界面

如果我们想要完成上面这样的界面,正常情况的XML是这样的:


image.png

首先是一个垂直的线性布局,里面一个自定义的Title,之后是五个 RelativeLayout, 最后是一个Button,那么如果利用Anko来进行编写是什么样的呢?

首先 创建一个实现 AnkoComponent接口的类(虽然可以直接在onCreate里面用DSL写,但是如果用这个 AnkoComponent,然后再安一个 Anko Support 的 插件 就有几率可以预览界面,但是经过实测,其实并不是那么好用 ,每次编辑完都要 build 一下才能预览 ,还不如直接在设备上调试。)

class SettingActivityUI(private val activity: BaseActivity) : AnkoComponent<SettingAnkoActivity> {
    override fun createView(ui: AnkoContext<SettingAnkoActivity>): View = with(ui) {
            verticalLayout {

                backgroundResource = R.color.bg_color

                commonTitle {
                    setLeftBackgroundResource(R.drawable.ic_return)
                    setTitle("设置")
                    setLeftClick { activity.finish() }
                }.lparams(width = matchParent, height = wrapContent)

                relativeLayout {
                    backgroundResource = R.color.white

                    textView {
                        id = ID_title
                        text = "个人设置"
                        textColorResource = R.color.c_333333
                        textSize = 15f
                        val leftDrawable = activity.resources.getDrawable(R.drawable.geren_icon)
                        leftDrawable.setBounds(0, 0, leftDrawable.minimumWidth, leftDrawable.minimumWidth)
                        setCompoundDrawables(leftDrawable, null, null, null)
                        compoundDrawablePadding = 16

                    }.lparams(wrapContent, wrapContent) {
                        centerVertically()
                        alignParentLeft()
                        setMargins(dip(16), 0, 0, 0)
                    }

                    imageView {
                        setImageResource(R.drawable.jiantou_you)
                    }.lparams(width = wrapContent, height = wrapContent) {
                        alignParentRight()
                        centerVertically()
                        setMargins(0, 0, dip(16), 0)
                    }

                }.lparams(matchParent, dip(50)).onClick {
                    find<TextView>(ID_title).text = "点击了个人设置"
//                    mBundle?.putString("sex", sex)
//                    IntentUtils.startActivity(activity, UserSettingActivity::class.java, mBundle)
                }

                relativeLayout {
                    backgroundResource = R.color.white

                    textView {
                        text = "意见反馈"
                        textColorResource = R.color.c_333333
                        textSize = 15f
                        val leftDrawable = activity.resources.getDrawable(R.drawable.yijian_icon)
                        leftDrawable.setBounds(0, 0, leftDrawable.minimumWidth, leftDrawable.minimumWidth)
                        setCompoundDrawables(leftDrawable, null, null, null)
                        compoundDrawablePadding = 16

                    }.lparams(wrapContent, wrapContent) {
                        centerVertically()
                        alignParentLeft()
                        setMargins(dip(16), 0, 0, 0)
                    }

                    imageView {
                        setImageResource(R.drawable.jiantou_you)
                    }.lparams(width = wrapContent, height = wrapContent) {
                        alignParentRight()
                        centerVertically()
                        setMargins(0, 0, dip(16), 0)
                    }

                }.lparams(matchParent, dip(50)).onClick {
                    IntentUtils.startActivity(activity, FeedbackActivity::class.java)
                }

                relativeLayout {
                    backgroundResource = R.color.white

                    textView {
                        text = "帮助中心"
                        textColorResource = R.color.c_333333
                        textSize = 15f
                        val leftDrawable = activity.resources.getDrawable(R.drawable.help_icon)
                        leftDrawable.setBounds(0, 0, leftDrawable.minimumWidth, leftDrawable.minimumWidth)
                        setCompoundDrawables(leftDrawable, null, null, null)
                        compoundDrawablePadding = 16

                    }.lparams(wrapContent, wrapContent) {
                        centerVertically()
                        alignParentLeft()
                        setMargins(dip(16), 0, 0, 0)
                    }

                    imageView {
                        setImageResource(R.drawable.jiantou_you)
                    }.lparams(width = wrapContent, height = wrapContent) {
                        alignParentRight()
                        centerVertically()
                        setMargins(0, 0, dip(16), 0)
                    }

                }.lparams(matchParent, dip(50)).onClick {
                    IntentUtils.startActivity(activity, HelpActivity::class.java)
                }

                relativeLayout {
                    backgroundResource = R.color.white

                    textView {
                        text = "安全中心"
                        textColorResource = R.color.c_333333
                        textSize = 15f
                        val leftDrawable = activity.resources.getDrawable(R.drawable.anquan_icon)
                        leftDrawable.setBounds(0, 0, leftDrawable.minimumWidth, leftDrawable.minimumWidth)
                        setCompoundDrawables(leftDrawable, null, null, null)
                        compoundDrawablePadding = 16

                    }.lparams(wrapContent, wrapContent) {
                        centerVertically()
                        alignParentLeft()
                        setMargins(dip(16), 0, 0, 0)
                    }

                    imageView {
                        setImageResource(R.drawable.jiantou_you)
                    }.lparams(width = wrapContent, height = wrapContent) {
                        alignParentRight()
                        centerVertically()
                        setMargins(0, 0, dip(16), 0)
                    }

                }.lparams(matchParent, dip(50)).onClick {
                    IntentUtils.startActivityForResult(activity, SecurityCenterActivity::class.java, mBundle, 100)
                }

                relativeLayout {
                    backgroundResource = R.color.white

                    textView {
                        text = "当前版本"
                        textColorResource = R.color.c_333333
                        textSize = 15f
                        val leftDrawable = activity.resources.getDrawable(R.drawable.aboutme_icon)
                        leftDrawable.setBounds(0, 0, leftDrawable.minimumWidth, leftDrawable.minimumWidth)
                        setCompoundDrawables(leftDrawable, null, null, null)
                        compoundDrawablePadding = 16

                    }.lparams(wrapContent, wrapContent) {
                        centerVertically()
                        alignParentLeft()
                        setMargins(dip(16), 0, 0, 0)
                    }

                    textView {
                        text = "v.${BuildConfig.VERSION_NAME}"
                        textColor = Color.parseColor("#999999")
                        textSize = 14f
                    }.lparams(width = wrapContent, height = wrapContent) {
                        alignParentRight()
                        centerVertically()
                        setMargins(0, 0, dip(16), 0)
                    }

                }.lparams(matchParent, dip(50)) {
                    topMargin = dip(16)
                }.onClick {
                    toast("正在检测,请稍后")
                    VersionUpdateUtils
                            .newInstance()
                            .latestVersionIndex(activity, activity.supportFragmentManager, "1")

                }

                button {
                    backgroundResource = R.drawable.shape_btn_bg
                    text = "退出当前账号"
                    textColorResource = R.color.white
                }.lparams(dip(300), wrapContent) {
                    topMargin = dip(30)
                    gravity = Gravity.CENTER
                }.onClick {
                            activity.alert {
                                with(activity){
                                    mApp.spUtils.putString(Constants.CCUSERID, "")
                                    mApp.spUtils.putString(Constants.TOKEN, "")
                                    val intent = Intent(this, MainActivity::class.java)
                                    intent.putExtra("flag", "exit")
                                    intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
                                    startActivity(intent)
                                    finish()
                                }

                            }.show()
                        }
            }
        }
    }

}

上面的代码中有一个自定义的view:CommonTileView,这个在Anko中是没有支持的,所以要怎么才能把自己写好的View也支持Anko呢?
我们只需要在任何kt文件中写下扩展就好了:

inline fun ViewManager.commonTitle(): CommonTileView = commonTitle {}

inline fun ViewManager.commonTitle(init: (@AnkoViewDslMarker CommonTileView).() -> Unit): CommonTileView {
    return ankoView(
            { CommonTileView(it) },
            theme = 0,
            init = init
    )
}

然而~~! 如果你不想凭借自己的想象写Anko的布局,那么你可以在安装了 Anko Support 插件之后 ,通过转换编写完的XML文件 ,自动生成 Anko Layouts的代码 在XML界面 ,点击工具栏上面的 ‘Code’ --> 'Convert to Anko Layouts DSL' ,这样就可以转换大部分XML的代码,在通过一丢丢的修改,就可以了,非常简单。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,085评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,654评论 2 59
  • 2019 年 12 月更新:就在几天前,Anko 已经正式宣布停止维护,官方宣称以后将推荐使用 Android J...
    _Preacher_阅读 12,704评论 2 37
  • Google在今年的IO大会上宣布,将Android开发的官方语言更换为Kotlin,作为跟着Google玩儿An...
    蓝灰_q阅读 76,713评论 31 490
  • 男:我一年就有五个月赚钱,一月算七千吧,五七三万五。不赚钱的时候,一月算五千,五七三万五,跟挣一个月工资也差不了多...
    天地大搏斗阅读 158评论 0 0