2016-02-26 100 views
6

Anko docs告诉我们如何将自定义视图添加到DSL。但是,如果我的自定义视图是视图组,则会出现问题。如何将自定义视图组添加到Anko 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一起使用的正确方法是什么?

回答

0

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

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

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

如果我想创建许多自定义视图组,添加对他们的Anko支持成为这种方法的一大痛苦。假设我有MyFrameLayout1,MyFrameLayout2,MyFrameLayout3类。他们基本上是FrameLayout的,所以我想要使用相同的布局参数。但我必须创建_FrameLayout1,_FrameLayout2,_FrameLaoyt3类,它们只是Anko的_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) 

这减少了复制/创造了许多自定义视图组时粘贴了很多。

+0

我提出了一个关于该问题https://github.com/Kotlin/anko/issues/152 – netimen

0

如果你到任何的安口的从你的代码lparams声明,你可以看到,里面安口生成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() 
    [email protected] = layoutParams 
    return this 
} 

(及以上重载对于不同的LayoutParams构造函数)

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


为了能够使用lparams您在安口DSL定制ViewGroup,你必须声明你的自定义视图代码中有类似的功能或功能,这将创建类的适当LayoutParams

如果你还想隐藏从DSL之外lparams功能,可以让你的MyFrameLayout的子类,并用它只有DSL代码,与MyFrameLayout别处工作本身。

之后,您可以在任何View内通过lparams在您通过init: MyFrameLayout.() -> Unitfun ViewManager.myFrameLayout的lambda中。

3

其实你只需要扩展ANKO并宣布你customview然后用它在DSL正常:

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

然后在DSL使用它通常

frameLayout { 
    customView() 
} 
2

如果从继承例如_RelativeLayout而不是RelativeLayout,您可以按照预期使用自定义布局。

相关问题