Kotlin for Android (IV): Custom Views and Android Extensions

After reading what extension functions and default values can do for you, you might be wondering what´s next. As we talked in first article about Kotlin, this language makes Android development much simpler and there are still some more things I´d like to talk about.

Custom Views

Kotlin, by default, only uses one constructor per class. This is usually enough, because using optional parameters we can create as many variations of the constructor as we may need. Here it is an example:

[kotlin]
class MyClass(param: Int, optParam1: String = "", optParam2: Int = 1)
{


 init {

 // Initialization code

 }

}
[/kotlin]

With a unique constructor, we now have four ways to create this class:

[kotlin]
val myClass1 = MyClass(1)
val myClass2 = MyClass(1, "hello")
val myClass3 = MyClass(param = 1, optParam2 = 4)
val myClass4 = MyClass(1, "hello", 4)
[/kotlin]

As you see, we get a whole bunch of combinations just by using optional parameters. But this leads to a problem if we are trying to create an Android custom view by extending one of the regular views. Custom views need to override more than one constructor to work properly. Luckily, we have a way to declare more constructors in way similar to what we do in Java. This is an example of an ImageView which preservers a squared ratio:

[kotlin]
class SquareImageView : ImageView {

constructor(context: Context) : super(context)

constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val width = getMeasuredWidth()
setMeasuredDimension(width, width)
}
}
[/kotlin]

Quite simple. It could probably be less verbose, but at least we have a way to do it.

Kotlin Android Extensions

If you didn’t know about Kotlin Android Extensions, you’re gonna love them. They will help us Android developers to access to the views declared in an XML in a much easier way. Some of you will remember Butterknife when you see it, but it´s even simpler to use.

Kotlin Android Extensions is basically a view binder that will let you use your XML views in your code by just using their id. It will automatically create properties for them without using any external annotation or findViewById methods.

To start using it, you´ll need to include the new plugin into the build.gradle:

[groovy]
apply plugin: ‘com.android.application’
apply plugin: ‘kotlin-android’
apply plugin: ‘kotlin-android-extensions

buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
[/groovy]

Imagine you have declared the next layout, called activity_main.xml:

[xml]
<FrameLayout

xmlns:android="…"

 android:id="@+id/frameLayout"

 android:orientation="vertical"

 android:layout_width="match_parent"

 android:layout_height="match_parent">



 <TextView

 android:id="@+id/welcomeText"

android:layout_width="wrap_content"

 android:layout_height="wrap_content"/>



</FrameLayout>
[/xml]

If you want to use these views in your activity, the only thing you need to do is importing the synthetic properties for that xml:

[kotlin]
import kotlinx.android.synthetic.main.<xml_name>.*
[/kotlin]

In our case, it will be just activity_main:

[kotlin]
import kotlinx.android.synthetic.main.activity_main.*
[/kotlin]

Now you can access your views by using its id:

[kotlin]
override fun onCreate(savedInstanceState: Bundle?) {

super<BaseActivity>.onCreate(savedInstanceState)
setContentView(R.id.main)

frameLayout.setVisibility(View.VISIBLE)

 welcomeText.setText("I´m a welcome text!!")

}
[/kotlin]

Conclusion

What it´s really promising about these two features is that it´s clear that the Kotlin team is very interested in making Android developers lives easier. They also released a library called Anko, a DSL to create Android layouts from Kotlin files. I´m not using its main functionality yet, but you can use it to simplify your code when dealing with Android views, and I have some examples of this in the Kotlin project I pushed to Github. You can take a look to see this and many other things.

Next article will cover the use of lambda expressions and how they can help us simplify our code and extend the language. Really interesting one! To me, the most powerful aspect of Kotlin when compared with Java 1.7.

18 thoughts on “Kotlin for Android (IV): Custom Views and Android Extensions”

  1. Is there a way that you know of to use the Android Extensions view injections from outside an Activity? I was trying to use it inside a ViewHolder, instead of a View.findById(), to no luck 🙁

    1. Android Extensions library supports extension properties for View as well as for Activity and Fragment classes. Just import everything in the `kotlinx.android.synthetic..view package and that’s it.

  2. Thanks! I had actually read that in the official docs but I hadn’t understood it properly. For the record, a for-dummies explanation of what you need to do is:

    1) Import kotlinx.android.synthetic..view.*
    2) Get a base view reference (i.e., view you’d otherwise call .findViewById() on)
    3) Reference your view like baseView.yourViewId

  3. utkan sargın

    hi
    i am getting this error

    Error:(11, 8) Unresolved reference: kotlinx

    and i can not find any solition

    can u help

    1. I also have this Problem and i am not able to fix that. I guess it has something to do with mixed up versions of several libs etc. I am using Android Studio 1.2.2 IntelliJ Kotlin Plugin 0.12.1218.Idea141.3 IntelliJ Kotlin Extensions For Android Plugin 0.12.613.Idea141.7 (<- wrong version?) added classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.12.1218' and classpath 'org.jetbrains.kotlin:kotlin-android-extensions:0.12.1218' to the main gradle and apply plugin: 'kotlin-android' and compile 'org.jetbrains.kotlin:kotlin-stdlib:0.12.1218' to the app gradle

    1. Antonio Leiva

      This is just code, not talking about any visual specifics here. What kind of screenshots would you find useful?

  4. Hi

    I have a custom view in my layout but when I try to import it with synthetic and use it it says:

    Overload resolution ambiguity. All this functions match.
    – View
    – CustomView

    It have both imports for View and for CustomView class, how can I import the custom view and avoid this warning?

  5. smallmouse09

    when i define a custom view.I also encount this problem.
    how can i bind the view with the id.

  6. How to add a view to an existing layout?

    I do following
    “`
    setContentView(R.layout.activity_dashboard)
    val photo = ImageView(this)
    “`

    Is this right and sufficient?

Comments are closed.