Как расширить ImageView в приложении Android-Scala?

Я пробовал много решений, найденных в google по ключевым словам: несколько конструкторов, scala, наследование, подклассы.

Кажется, что никто не работает по этому поводу. ImageView имеет три конструктора:

 ImageView(context) ImageView(context,attribute set) ImageView(context,attribute set, style) 

В scala вы можете только расширить один из них. И решение использования более полного конструктора ( ImageView(context,attribute set, style) ) и передачи значений по умолчанию не работает либо потому, что конструктор ImageView(context) делает что-то совершенно иное, чем два других конструктора.

Некоторые решения использования признака или сопутствующего объекта не работают, потому что CustomView должен быть классом! Я имею в виду, что я не единственный, кто использует этот класс (чтобы я мог написать код scala любым способом, я хотел) есть также android-sdk, который использует этот класс, и да, он должен быть классом.

Цель состоит в том, чтобы иметь CustomView, который расширяет ImageView и все эти работы:

 new CustomView(context) new CustomView(context,attribute set) new CustomView(context,attribute set, style) 

Пожалуйста, дайте мне знать, если вам понадобится дополнительное разъяснение по этому сложному вопросу!

Solutions Collecting From Web of "Как расширить ImageView в приложении Android-Scala?"

В соответствии с View документации Android View View(Context) используется при построении из кода и View(Context, AttributeSet) и View(Context, AttributeSet, int) (и поскольку API-уровень 21 View(Context, AttributeSet, int, int) ) является Используется, когда представление завышено от XML.

Конструктор 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 } 

Затем «конструктор кода» можно использовать как:

 var myView = MyView(context) 

(Не реальный конструктор).

А другой раз:

 var myView2 = new MyView(context, attrs) var myView3 = new MyView(context, attrs, defStyle) 

Который так ожидает SDK.

Аналогично, для уровня API 21 и выше class может быть определен как:

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

И четвертый конструктор может быть использован как:

 var myView4 = new MyView(context, attrs, defStyle, defStyleRes) 

Обновить:

Это становится немного сложнее, если вы попытаетесь вызвать protected метод в View , например setMeasuredDimension(int, int) из setMeasuredDimension(int, int) . Защищенные 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) } } 

По словам Мартина Одерского (создателя Скалы), это невозможно.

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

«Существует ли способ вызвать разные суперконструкторы в разных конструкторах классов – или все должны перейти к основному конструктору и поддерживается только один супер-конструктор?

Нет, он должен пройти через главного конструктора. Это одна деталь, где Scala более ограничительна, чем Java ».

Я думаю, что ваш лучший подход – реализовать свои взгляды на Java.

Похоже, вам просто лучше писать подкласс в 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 

В коде приложения вы можете использовать одну, две или три версии аргумента следующим образом:

 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) 

Похоже, много работы. В зависимости от ваших целей вы можете добавить дополнительное поведение с implicits:

 implicit def imageViewToCustomView(view: ImageView) = new { def foo = ... } 

Этот вопрос привел меня к нескольким проектным соображениям, которые я хотел бы поделиться с вами.

Мое первое соображение состоит в том, что если класс Java был правильно спроектирован, наличие нескольких конструкторов должно быть признаком того, что некоторые свойства класса могут иметь значение по умолчанию .

Scala предоставляет значения по умолчанию в качестве языковой функции , поэтому вам не нужно беспокоиться о предоставлении нескольких конструкторов вообще, вы можете просто предоставить значение по умолчанию для некоторых аргументов вашего конструктора. Такой подход приводит к значительно более чистому API, чем три разных конструктора, которые производят такое поведение, поскольку вы четко указываете, почему вам не нужно указывать все параметры.

Мое второе соображение заключается в том, что это не всегда применимо, если вы распространяете классы сторонней библиотеки. Однако:

  • Если вы расширяете класс библиотеки с открытым исходным кодом и класс правильно разработан, вы можете просто исследовать значения по умолчанию аргумента конструктора
  • Если вы расширяете класс, который неправильно разработан (т. Е. Когда перегруженные конструкторы не являются API-интерфейсом по умолчанию для некоторых параметров) или где у вас нет доступа к источнику, вы можете заменить наследование композицией и обеспечить неявное преобразование.

     class CustomView(c: Context, a: Option[AttributeSet]=None, s: Option[Int]=None){ private val underlyingView:ImageView = if(a.isDefined) if (s.isDefined) new ImageView(c,a.get,s.get) else new ImageView(c,a.get) else new ImageView(c) } object CustomView { implicit def asImageView(customView:CustomView):ImageView = customView.underlyingView }