如何将自定义视图组添加到Anko 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一起使用的正确方法是什么?
其实你只需要扩展anko并声明你的customview,然后在DSL中正常使用它:
public inline fun ViewManager.customView() = customView {} public inline fun ViewManager.customView(init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, init)
然后正常使用它在DSL
frameLayout { customView() }
如果您从_RelativeLayout
而不是RelativeLayout
继承,则可以按照您的预期使用自定义布局。
如果你从你的代码中lparams
的lparams
声明,你可以看到lparams
里面生成了DSL代码, lparams
是T: 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
构造函数)
它是在一个类中声明的,所以它只能在具有该类的接收器的函数中看到,请参阅有关此DSL编程方法的另一个问题 。
为了能够在您的自定义ViewGroup
中使用lparams
,您必须在自定义视图代码中声明一个或多个类似的函数,这将为您的类创建适当的LayoutParams
。
如果你还想隐藏DSL之外的lparams
函数,你可以创建一个MyFrameLayout
的子类,只在DSL代码中使用它,在其他地方使用MyFrameLayout
。
在那之后,你可以调用任何View
里的lambda init: MyFrameLayout.() -> Unit
作为init: MyFrameLayout.() -> Unit
fun ViewManager.myFrameLayout
。
如果我们看看frameLayout
来源,我们可以看到frameLayout
返回一个_FrameLayout
类的实例,在这里定义了这些lparams
函数。 根据我的理解,这是必要的,所以这些lparams
函数只能在布局构建代码中使用。
在Anko的Layouts.kt
文件中,每个支持的ViewGroup
都有这些_<ViewGroup>
类。
因此,支持自定义视图组的直接方法是使用lparams
方法实现来创建_<ViewGroup>
类。 问题是这个_<ViewGroup>
类通常比我的<ViewGroup>
本身包含更多的代码!
如果我想创建许多自定义视图组,添加Anko支持他们成为这种方法很大的痛苦。 比方说,我有MyFrameLayout1
, MyFrameLayout2
, MyFrameLayout3
类。 他们基本上是FrameLayout
的,所以我想要使用相同的布局参数。 但是我必须创建_FrameLayout1
, _FrameLayout2
, _FrameLaoyt3
类, _FrameLaoyt3
类只是_FrameLaoyt3
复制/粘贴。
所以我稍微改进了这个方法。 我创建一个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)
这在创建许多自定义视图组时会减少很多复制/粘贴操作。