如何在Android-Scala应用程序中扩展ImageView?

Geo*_*los 11 inheritance android scala multiple-constructors

我通过关键字在谷歌尝试了许多解决方案:多个构造函数,scala,继承,子类.

似乎没有人适合这个场合.ImageView有三个构造函数:

ImageView(context)
ImageView(context,attribute set)
ImageView(context,attribute set, style)
Run Code Online (Sandbox Code Playgroud)

在scala中,您只能扩展其中一个.使用更完整的构造函数(ImageView(context,attribute set, style))并传递默认值的解决方案也不起作用,因为构造函数ImageView(context)执行的操作与其他两个构造函数完全不同.

使用特征或伴随对象的一些解决方案似乎不起作用,因为CustomView必须是一个类!我的意思是我不是唯一一个使用这个类的人(所以我可以按照我想要的方式编写scala代码)还有使用这个类的android-sdk,是的,它必须是一个类.

target是一个扩展ImageView的CustomView,所有这些工作:

new CustomView(context)
new CustomView(context,attribute set)
new CustomView(context,attribute set, style)
Run Code Online (Sandbox Code Playgroud)

如果您需要进一步澄清这个棘手的问题,请告诉我!

Rui*_*ves 7

根据Martin Odersky(Scala的创建者)的说法,这是不可能的.

http://scala-programming-language.1934581.n4.nabble.com/scala-calling-different-super-constructors-td1994456.html中:

"有没有办法在不同的类构造函数中调用不同的超级构造函数 - 或者是否所有必须转到主构造函数并且只支持一个超级构造函数?

不,它必须通过主构造函数.这是Scala比Java更具限制性的一个细节."

我认为您最好的方法是在Java中实现您的视图.


yak*_*ver 5

听起来你可能只是更好地在Java中编写子类.否则,如果您对使用三参数构造函数的SDK的假设是正确的,那么您可以使用特征和具有伴随对象的类.SDK将使用三个参数构造函数CustomView,它还实现了一个包含您需要的任何其他行为的特征:

trait TCustomView {
  // additional behavior here
}

final class CustomView(context: Context, attributes: AttributeSet, style: Int)
  extends ImageView(context, attributes, style) with TCustomView
Run Code Online (Sandbox Code Playgroud)

在应用程序代码中,您可以使用以下方式使用一个,两个或三个参数版本:

object CustomView {
  def apply(c: Context, a: AttributeSet, s: Int) =
    new ImageView(c, a, s) with TCustomView
  def apply(context: Context, attributes: AttributeSet) =
    new ImageView(context, attributes) with TCustomView
  def apply(context: Context) = new ImageView(context) with TCustomView
}

CustomView(context)
CustomView(context, attributes)
CustomView(context, attributes, style)
Run Code Online (Sandbox Code Playgroud)

好像很多工作.根据您的目标,您可以使用implicit添加其他行为:

implicit def imageViewToCustomView(view: ImageView) = new {
  def foo = ...
}
Run Code Online (Sandbox Code Playgroud)


pet*_*ter 0

根据AndroidView文档, View(Context)当从代码构造时使用 和View(Context, AttributeSet)View(Context, AttributeSet, int)并且自 API 级别 21 开始)当从 XML 扩充View(Context, AttributeSet, int, int)时使用。View

XML 构造函数都只调用同一个构造函数,参数最多的构造函数也是唯一具有实际实现的构造函数,因此我们可以在 Scala 中使用默认参数。另一方面,“代码构造函数”可能有另一种实现,因此最好也从 Scala 实际调用。

下面的实现可能是一个解决方案:

private trait MyViewTrait extends View {
  // implementation
} 

class MyView(context: Context, attrs: AttributeSet, defStyle: Int = 0)
    extends View(context, attrs, defStyle) with MyViewTrait {}

object MyView {
  def apply(context: Context) = new View(context) with MyViewTrait
}
Run Code Online (Sandbox Code Playgroud)

然后可以像这样使用“代码构造函数”:

var myView = MyView(context)
Run Code Online (Sandbox Code Playgroud)

(不是真正的构造函数)。

另一个曾经喜欢:

var myView2 = new MyView(context, attrs)
var myView3 = new MyView(context, attrs, defStyle)
Run Code Online (Sandbox Code Playgroud)

这是 SDK 期望的方式。

类似地,对于 API 级别 21 及更高级别,class可以定义为:

class MyView(context: Context, attrs: AttributeSet, defStyle: Int = 0, defStyleRes: Int = 0)
    extends View(context, attrs, defStyle, defStyleRes) with MyViewTrait {}
Run Code Online (Sandbox Code Playgroud)

第四个构造函数可以像这样使用:

var myView4 = new MyView(context, attrs, defStyle, defStyleRes)
Run Code Online (Sandbox Code Playgroud)

更新:

如果您尝试调用protected中的方法View(例如setMeasuredDimension(int, int)trait. Java 受保护的方法不能从特征中调用。class解决方法是在和实现中实现访问器object

private trait MyViewTrait extends View {
  protected def setMeasuredDimensionAccessor(w: Int, h: Int): Unit
  def callingSetMeasuredDimensionAccessor(): Unit = {
    setMeasuredDimensionAccessor(1, 2)
  }
} 

class MyView(context: Context, attrs: AttributeSet, defStyle: Int = 0)
    extends View(context, attrs, defStyle) with MyViewTrait {
  override protected def setMeasuredDimensionAccessor(w: Int, h: Int) =
    setMeasuredDimension(w, h)
}

object MyView {
  def apply(context: Context) = new View(context) with MyViewTrait {
    override protected def setMeasuredDimensionAccessor(w: Int, h: Int) =
      setMeasuredDimension(w, h)
  }
}
Run Code Online (Sandbox Code Playgroud)