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一起使用的正确方法是什么?
答案 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代码中,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
构造函数的更多重载)
它在一个类中声明,因此它仅在具有该类接收器的函数中可见,请参阅another question关于这种DSL编程方法。
为了能够在Anko DSL中使用lparams
作为自定义ViewGroup
,您必须在自定义视图代码中声明一个类似的函数,这将创建一个合适的{{1为你的班级。
如果您还想在DSL外部隐藏LayoutParams
功能,您可以创建lparams
的子类,并仅在DSL代码中使用它,在其他地方使用MyFrameLayout
。
之后,您可以在lambda中的MyFrameLayout
内调用lparams
,View
传递给init: MyFrameLayout.() -> Unit
。
答案 3 :(得分:0)
如果我们查看Anko源代码,我们可以看到frameLayout
实际返回_FrameLayout
类的实例,其中定义了这些lparams
函数。根据我的理解,这是必需的,因此这些lparams
函数仅在布局构建代码中可用。
在Anko的Layouts.kt
文件中,每个支持的_<ViewGroup>
都有这些ViewGroup
个类。
因此,支持自定义视图组的直接方法是使用_<ViewGroup>
方法实现创建lparams
类。问题是这个_<ViewGroup>
类通常包含的代码比<ViewGroup>
本身多得多!
如果我想创建许多自定义视图组,使用这种方法添加Anko支持就会变得非常痛苦。我们说我有MyFrameLayout1
,MyFrameLayout2
,MyFrameLayout3
个类。它们基本上是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)
在创建许多自定义视图组时,这会大大减少复制/粘贴。