如何将自定义视图组添加到Anko DSL?

时间:2016-02-26 12:32:58

标签: kotlin anko

Anko docs告诉我们如何向DSL添加自定义视图。但是,如果我的自定义视图是一个视图组,则会出现问题。

class MyFrameLayout(context: Context) : FrameLayout(context)

fun ViewManager.myFrameLayout(init: MyFrameLayout.() -> Unit = {}) = ankoView({ MyFrameLayout(it) }, init)

class MyUI : AnkoComponent<Fragment> {
    override fun createView(ui: AnkoContext<Fragment>) = with(ui) {

        myFrameLayout {
            textView("hello").lparams { // error: Unresolved reference: lparams
                bottomMargin = dip(40)
            }
        }
    }
}

但如果我将myFrameLayout调用更改为frameLayout,则可以正常工作。那么使视图组与Anko DSL一起使用的正确方法是什么?

4 个答案:

答案 0 :(得分:6)

实际上你只需要扩展anko并声明你的自定义视图然后通常在DSL中使用它:

public inline fun ViewManager.customView() = customView {}
public inline fun ViewManager.customView(init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, init)

然后通常在DSL中使用它

frameLayout {
    customView()
}

答案 1 :(得分:2)

如果你继承自例如_RelativeLayout代替RelativeLayout,您可以按预期使用自定义布局。

答案 2 :(得分:0)

如果您从代码中查看任何Anko的lparams声明,您可以看到在Anko生成的DSL代码中,lparamsT: View的扩展函数,看起来像这样:

fun <T: View> T.lparams(
        width: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
        height: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
        init: android.widget.FrameLayout.LayoutParams.() -> Unit = defaultInit
): T {
    val layoutParams = android.widget.FrameLayout.LayoutParams(width, height)
    layoutParams.init()
    this@lparams.layoutParams = layoutParams
    return this
}

(以及不同LayoutParams构造函数的更多重载)

它在一个类中声明,因此它仅在具有该类接收器的函数中可见,请参阅another question关于这种DSL编程方法。

为了能够在Anko DSL中使用lparams作为自定义ViewGroup,您必须在自定义视图代码中声明一个类似的函数,这将创建一个合适的{{1为你的班级。

如果您还想在DSL外部隐藏LayoutParams功能,您可以创建lparams的子类,并仅在DSL代码中使用它,在其他地方使用MyFrameLayout

之后,您可以在lambda中的MyFrameLayout内调用lparamsView传递给init: MyFrameLayout.() -> Unit

答案 3 :(得分:0)

如果我们查看Anko源代码,我们可以看到frameLayout实际返回_FrameLayout类的实例,其中定义了这些lparams函数。根据我的理解,这是必需的,因此这些lparams函数仅在布局构建代码中可用。

在Anko的Layouts.kt文件中,每个支持的_<ViewGroup>都有这些ViewGroup个类。

因此,支持自定义视图组的直接方法是使用_<ViewGroup>方法实现创建lparams类。问题是这个_<ViewGroup>类通常包含的代码比<ViewGroup>本身多得多!

如果我想创建许多自定义视图组,使用这种方法添加Anko支持就会变得非常痛苦。我们说我有MyFrameLayout1MyFrameLayout2MyFrameLayout3个类。它们基本上是FrameLayout,因此我希望使用相同的布局参数。但我必须创建_FrameLayout1_FrameLayout2_FrameLaoyt3类,这些类只是Anko&#39; _FrameLayout的复制/粘贴。

所以我略微改进了这种方法。我创建了一个interface _FrameLayout

interface _FrameLayout {
    // copy/paste from Anko's _FrameLayout
}

现在支持我必须的任何自定义FrameLayout子类:

class _MyFrameLayout(ctx: Context) : MyFrameLayout(ctx), _FrameLayout

fun ViewManager.myFrameLayout(init: _MyFrameLayout.() -> Unit = {})= ankoView({ _MyFrameLayout(it) }, init) 

在创建许多自定义视图组时,这会大大减少复制/粘贴。