Kotlin布局框架anko源码刨析

有段时间没有写贴子,不管再怎么学好记性不如烂笔头,有空还是将脑袋里的东西记录一下的好,省的过个几个月不用又忘了。

anko作为kotlin开发android来说加入了很多简洁的语法,最注目的就是直接在代码里面写控件布局,而且看起来还很简洁像极了ios,android终于成熟起来了,越来越像ios开发了,anko做为kotlin的开发的框架将kotlin的简洁的语法发挥的淋漓尽致。

如果你写代码很忙,没时间去读一本Kotlin书的话了解kotlin语法,那么不妨去的看一下anko源码,一天也就通晓了kotlin的所有用法。

下面来看一下简单的登录用anko怎么写

verticalLayout(){
            padding = dip(30)
            editText {
                hint = "Name"
                textSize = 24f
                onClick {  }
            }
            editText {
                hint = "Password"
                textSize = 24f

            }.lparams(0, wrapContent){

            }
            button("Login") {
                textSize = 26f
            }
        }

看这代码多么的简洁,最外层用了垂直的线性布局,紧跟着两个输入框,然后一个登陆的按钮就直接完成了登陆的界面,而且不用调用setContentView布局就会加载显示,这比java写android要简洁太多了,写这个布局用java你得new四次控件,不断的set设置属性,不断add添加view,表示一年多的kotlin,再也不想用java了。

就算kotlin语法上要简洁,但也不可能像上面写法那么简洁,所有anko做了很多封装

inline fun Activity.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

这个垂直线性布局,anko是用了扩展函数实现的,然后它还是内联的,编译器会在编译的时候会将方法去掉。

可以看出此方法两个参数一个是主题一个是闭包函数,闭包函数在我看来就是和c的函数指针差不多,传的就是函数实现的指针

随后调用ankoView方法

inline fun <T : View> Activity.ankoView(factory: (ctx: Context) -> T, theme: Int, init: T.() -> Unit): T {
    val ctx = AnkoInternals.wrapContextIfNeeded(this, theme)
    val view = factory(ctx)
    view.init()
    AnkoInternals.addView(this, view)
    return view
}

这两个方法的前缀都是加了Activity.,所以这两个方法都属于Activity的扩展方法,所以可以直接在activity方法里面直接调用,ankoView方法第一个参数也是一个方法闭包,返回的是View类型的,第三个参数又是一个闭包是调用了当前T的方法的闭包,那么传入的参数$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY是一个返回View的方法

val VERTICAL_LAYOUT_FACTORY = { ctx: Context ->
        val view = _LinearLayout(ctx)
        view.orientation = LinearLayout.VERTICAL
        view
    }

可以看出传入的闭包函数最终创建了垂直的线性布局_LinearLayout

open class _LinearLayout(ctx: Context): LinearLayout(ctx)

接着看AnkoInternals.wrapContextIfNeeded函数

fun wrapContextIfNeeded(ctx: Context, theme: Int): Context {
        return if (theme != 0 && (ctx !is AnkoContextThemeWrapper || ctx.theme != theme)) {
            // If the context isn't a ContextThemeWrapper, or it is but does not have
            // the same theme as we need, wrap it in a new wrapper
            AnkoContextThemeWrapper(ctx, theme)
        } else {
            ctx
        }
    }

这里就是创建了新的Context,然后继续看val view = factory(ctx)这个代码就是调用了VERTICAL_LAYOUT_FACTORY这个方法,factory可以看做VERTICAL_LAYOUT_FACTORY方法的方法指针。

那么创建完View之后就调用了view.init()方法,这个方法其实就是

verticalLayout(){
            
        }

verticalLayout闭包里的代码,最后调用 AnkoInternals.addView(this, view)将布局绑定到到Activity上,这里的this就是activity对象

 override fun addView(view: View?, params: ViewGroup.LayoutParams?) {
        if (view == null) return

        if (myView != null) {
            alreadyHasView()
        }

        this.myView = view

        if (setContentView) {
            doAddView(ctx, view)
        }
    }

    private fun doAddView(context: Context, view: View) {
        when (context) {
            is Activity -> context.setContentView(view)
            is ContextWrapper -> doAddView(context.baseContext, view)
            else -> throw IllegalStateException("Context is not an Activity, can't set content view")
        }
    }

最终自己调用setContentView将布局和Activity绑定然后显示出来,不用我们自己写了

其实看完这些anko写布局为什么这么简洁就是用了Kotlin的扩展函数写法,将繁琐的布局控件声明,添加都帮我们实现了,所以才会用起来这么简单。

发布了49 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/xiatiandefeiyu/article/details/104948862