使用Kotlin自定义Android视图

我正在尝试在我的Android项目中使用Kotlin。 我需要创建自定义视图类。 每个自定义视图有两个重要的构造函数:

public class MyView extends View { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } } 

MyView(Context)用于在代码中实例化视图,当从XML扩充布局时, MyView(Context, AttributeSet)由布局inflater调用。

对这个问题的回答建议我使用默认值或工厂方法的构造函数。 但是,这里是我们所拥有的:

工厂方法:

 fun MyView(c: Context) = MyView(c, attrs) //attrs is nowhere to get class MyView(c: Context, attrs: AttributeSet) : View(c, attrs) { ... } 

要么

 fun MyView(c: Context, attrs: AttributeSet) = MyView(c) //no way to pass attrs. //layout inflater can't use //factory methods class MyView(c: Context) : View(c) { ... } 

具有默认值的构造函数:

 class MyView(c: Context, attrs: AttributeSet? = null) : View(c, attrs) { ... } //here compiler complains that //"None of the following functions can be called with the arguments supplied." //because I specify AttributeSet as nullable, which it can't be. //Anyway, View(Context,null) is not equivalent to View(Context,AttributeSet) 

这个难题如何解决?


更新:好像我们可以使用View(Context, null)超类的构造函数而不是View(Context) ,所以工厂方法似乎是解决方案。 但即使如此,我无法让我的代码工作:

 fun MyView(c: Context) = MyView(c, null) //compilation error here, attrs can't be null class MyView(c: Context, attrs: AttributeSet) : View(c, attrs) { ... } 

要么

 fun MyView(c: Context) = MyView(c, null) class MyView(c: Context, attrs: AttributeSet?) : View(c, attrs) { ... } //compilation error: "None of the following functions can be called with //the arguments supplied." attrs in superclass constructor is non-null 

Kotlin自M11于2015年3月19日发布以来,支持多种构造函数。 语法如下:

 class MyView : View { constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) { // ... } constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {} } 

更多信息在这里和这里 。

你应该使用注释JvmOverloads (就像在Kotlin 1.0中看起来一样),你可以这样写代码:

 class CustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : View(context, attrs, defStyle) 

这将产生3个构造函数,就像你最想要的一样。

从文档引用:

对于每个具有默认值的参数,这将会生成一个额外的重载,该参数将删除参数列表中的该参数及其右侧的所有参数。

这似乎是一个问题。 我从来没有遇到过这种情况,因为我的自定义视图或者只能在xml中创建,或者只能在代码中创建,但是我可以看到这会出现在哪里。

据我所知,有两种方法:

1)使用attrs构造函数。 在xml中使用视图将正常工作。 在代码中,您需要为您的视图添加所需标记的xml资源,并将其转换为属性集:

 val parser = resources.getXml(R.xml.my_view_attrs) val attrs = Xml.asAttributeSet(parser) val view = MyView(context, attrs) 

2)使用没有attrs的构造函数。 你不能直接在你的xml中放置视图,但是很容易将一个FrameLayout放置在xml中,并通过代码添加视图。

Custome View与kotlin这里的示例代码。

 class TextViewLight : TextView { constructor(context: Context) : super(context){ val typeface = ResourcesCompat.getFont(context, R.font.ccbackbeat_light_5); setTypeface(typeface) } constructor(context: Context, attrs : AttributeSet) : super(context,attrs){ val typeface = ResourcesCompat.getFont(context, R.font.ccbackbeat_light_5); setTypeface(typeface) } constructor(context: Context, attrs: AttributeSet , defStyleAttr : Int) : super(context, attrs, defStyleAttr){ val typeface = ResourcesCompat.getFont(context, R.font.ccbackbeat_light_5); setTypeface(typeface) } } 

您可以从JetBrains尝试新的Kotlin Library Anko (也可以在github上贡献)。 目前它处于测试阶段,但您可以使用此类代码创建视图

  button("Click me") { textSize = 18f onClick { toast("Clicked!") } } 

看看这个库