2016-02-26 102 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,您可以按照預期使用自定義佈局。

相關問題