And*_*nko 41 android constructor kotlin
我正在尝试在我的Android项目中使用Kotlin.我需要创建自定义视图类.每个自定义视图都有两个重要的构造函数
public class MyView extends View {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
Run Code Online (Sandbox Code Playgroud)
MyView(Context)用于在代码中实例化视图,并MyView(Context, AttributeSet)在从XML 扩展布局时由布局inflater调用.
对这个问题的回答表明我使用默认值或工厂方法的构造函数.但这就是我们所拥有的:
工厂方法:
fun MyView(c: Context) = MyView(c, attrs) //attrs is nowhere to get
class MyView(c: Context, attrs: AttributeSet) : View(c, attrs) { ... }
Run Code Online (Sandbox Code Playgroud)
要么
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) { ... }
Run Code Online (Sandbox Code Playgroud)
具有默认值的构造方法:
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)
Run Code Online (Sandbox Code Playgroud)
如何解决这个难题?
更新:似乎我们可以使用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) { ... }
Run Code Online (Sandbox Code Playgroud)
要么
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
Run Code Online (Sandbox Code Playgroud)
col*_*iot 52
你应该使用注释JvmOverloads(就像在Kotlin 1.0中看起来一样),你可以编写如下代码:
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : View(context, attrs, defStyle)
Run Code Online (Sandbox Code Playgroud)
这将生成3个构造函数,就像您最想要的那样.
从文档引用:
对于具有默认值的每个参数,这将生成一个额外的重载,该重载具有此参数,并且删除了参数列表中右侧的所有参数.
aga*_*aga 43
自2015年3月19日发布的M11以来,Kotlin支持多个构造函数.语法如下:
class MyView : View {
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
// ...
}
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {}
}
Run Code Online (Sandbox Code Playgroud)
编辑:您还可以使用@JvmOverloads注释,以便Kotlin为您自动生成所需的构造函数:
class MyView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : View(context, attrs, defStyle)
Run Code Online (Sandbox Code Playgroud)
但要注意,因为这种方法有时会导致意外结果,具体取决于您继承的类如何定义其构造函数.在该文章中给出了可能发生的事情的良好解释.
Custome View这里科特林的示例代码.
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)
}
}
Run Code Online (Sandbox Code Playgroud)
这确实是一个问题.我从来没有遇到过这种情况,因为我的自定义视图要么只在xml中创建,要么只在代码中创建,但我可以看到它会出现在哪里.
据我所知,有两种解决方法:
1)使用带有attrs的构造函数.使用xml中的视图可以正常工作.在代码中,您需要使用所需的视图标记为xml资源充气,并将其转换为属性集:
val parser = resources.getXml(R.xml.my_view_attrs)
val attrs = Xml.asAttributeSet(parser)
val view = MyView(context, attrs)
Run Code Online (Sandbox Code Playgroud)
2)使用没有attrs的构造函数.您不能将视图直接放在xml中,但很容易将FrameLayout放在xml中并通过代码将视图添加到其中.
TL;DR大多数时候,只需将自定义视图定义为:
class MyView(context: Context, attrs: AttributeSet?) : FooView(context, attrs)
Run Code Online (Sandbox Code Playgroud)
鉴于此 Java 代码:
public final class MyView extends View {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
Run Code Online (Sandbox Code Playgroud)
它的 Kotlin 等效项将使用辅助构造函数:
class MyView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
}
Run Code Online (Sandbox Code Playgroud)
当您确实想根据视图是在代码中创建还是从 XML 膨胀来调用不同的超类构造函数时,该语法很有用。我所知道的唯一情况是当您View直接扩展类时。
您可以使用带有默认参数和@JvmOverloads注释的主构造函数,否则:
class MyView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs)
Run Code Online (Sandbox Code Playgroud)
你并不需要@JvmOverloads constructor,如果你不打算从Java调用它。
而如果你只从XML膨胀的观点,那么你可以去从最简单的:
class MyView(context: Context, attrs: AttributeSet?) : View(context, attrs)
Run Code Online (Sandbox Code Playgroud)
如果您的类open用于扩展并且您需要保留父类的样式,则您想回到仅使用辅助构造函数的第一个变体:
open class MyView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
}
Run Code Online (Sandbox Code Playgroud)
但是如果你想要一个open覆盖父样式并让它的子类也覆盖它的类,你应该没问题@JvmOverloads:
open class MyView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.customStyle,
defStyleRes: Int = R.style.CustomStyle
) : View(context, attrs, defStyleAttr, defStyleRes)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16871 次 |
| 最近记录: |