Пользовательские виды Android с Kotlin



Я пытаюсь использовать Kotlin в своем Android-проекте. Мне нужно создать пользовательский класс представления. Каждое пользовательское представление имеет два важных конструктора:



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

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


MyView(Context) используется для создания экземпляра представления в коде, и MyView(Context, AttributeSet) вызывается layout inflater при раздувании layout из XML.



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



Фабричный метод:



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)


Как можно разрешить эту загадку?





UPDATE: Похоже, что мы можем использовать конструктор суперкласса 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
702   5  

5 ответов:

Kotlin поддерживает несколько конструкторов начиная с M11, который был выпущен 19.03.2015. Синтаксис выглядит следующим образом:

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 конструктора, как вы, скорее всего, хотели.

Цитата из docs :

Для каждого параметра со значением по умолчанию будет сгенерировано одно значение. дополнительная перегрузка, которая имеет этот параметр и все параметры, чтобы справа от него в списке параметров удалено.

Похоже, это действительно проблема. Я никогда не сталкивался с этим, потому что мои пользовательские представления были созданы либо только в 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)
}

}

Вы можете попробовать новую библиотеку Anko для Kotlin из JetBrains (также вы можете внести свой вклад в github). В настоящее время он находится в бета-версии, но вы можете создавать представления с таким кодом

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

Взгляните на эту библиотеку

Comments

    Ничего не найдено.