Building a Custom Component for Android with Kotlin or QML – A Comparison

When creating UIs it’s a common task to build your own set of reusable UI Components, if you dont want to rely on the built-in set of the framework.
I was very curious how this is done in native Android app-development and how this fancy new language Kotlin works in this context.
A quick search brought me to this excellent tutorial from Eley “Building Custom Component with Kotlin”.

So here is the goal:

Create a reusable component which contains a label, an editable textline and a switch, formatted as you can see in the picture below (original picture slightly adjusted).

I will show the lines of code you need to achieve this goal with Native Android + Kotlin on the one hand and Android -styled QML on the other hand.

Version 1: Native Android with Kotlin

For a detailed description please check the original source.
First you need a layout xml file which contains the needed TextView as Title, an EditView a Switch and a Layout to place everything properly:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android=""

        android:layout_height="wrap_content" />


            android:layout_weight="1" />

            android:layout_marginTop="6dp" />


Next we need a class file, written in Kotlin to initiate the visual elements an bring them to live:

package com.elyeproj.myapplication

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout

class CustomComponent @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyle: Int = 0,
        defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyle, defStyleRes) {

    init {
        LayoutInflater.from(context).inflate(R.layout.view_custom_component, this, true)
        orientation = VERTICAL

        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it, R.styleable.custom_component_attributes, 0, 0)
            val title = resources.getText(typedArray
                    .getResourceId(R.styleable.custom_component_attributes_custom_component_title, R.string.component_one))

            my_title.text = title
            my_edit.hint = "${resources.getString(R.string.hint_text)} $title"



To expose attributes of the component we need a third file, called attrs.xml which is used inside the class constructor.

<?xml version="1.0" encoding="utf-8"?>
    <declare-styleable name="custom_component_attributes">
        <attr name="custom_component_title" format="reference" />

Now we are ready to use it in a layout file:

    app:custom_component_title="@string/component_one" />


Version 2: QML

The entire component consists of the following singe QML file, called “CustomComponent.qml”.

import QtQuick 2.9
import QtQuick.Controls 2.2

Column {
    id: componentRoot

    property alias labelText: label.text
    property alias editText: textField.text
    property alias checked: switchButton.checked
    signal switchClicked(bool checked)

    width: parent.width -6
    height: 60
    x: 6

    Label {
        id: label
        text: "Custom Component"
        font.pixelSize: 16
        font.weight: Font.DemiBold
        opacity: 0.8

    Item {
        width: parent.width
        height: textField.height

        TextField {
            id: textField
            placeholderText: "Type something for " + label.text
            anchors.left: parent.left
            anchors.right: switchButton.left

        Switch {
            id: switchButton
            anchors.right: parent.right
            onClicked: componentRoot.switchClicked(checked)

The root class of the component is a Column to layout the content vertically. It contains the Label and a second Item with contains a TextField and a Switch for which I chose the anchors system to set the layout. Three properties of content-controls are exposed easily by using property alias.
Qt creates automatically “on<property>Changed” signals (=events) to make these properties observable from outside. In this case onLabelTextChanged, onEditTextChanged and onCheckedChanged. In addition I have added a new signal (=event) called switchClicked() which is triggered when the user clicks on the switch. This helps to seperate user-inputs from programmatically changes.

The component can be used instantly when it is in the same directory, the filename “CustomComponent” is the class-name. This is the complete code of the test-application:

import QtQuick 2.9
import QtQuick.Controls 2.2

ApplicationWindow {
    id: app
    visible: true
    width: 400
    height: 620

    header: ToolBar {
        Label {
            text: "My Application"
            x: 14
            anchors.verticalCenter: parent.verticalCenter
            font.pixelSize: 16
            font.weight: Font.DemiBold

    Page {

        anchors.fill: parent

        Column {
            y: 6
             width: parent.width

             CustomComponent {
                 labelText: "Custom Component 1"
                 onEditTextChanged: console.log("User typed: " + editText)

             CustomComponent {
                 labelText: "Custom Component 2"
                 checked: true
                 onCheckedChanged: console.log("checked changed to: " + checked)

             CustomComponent {
                 labelText: "Custom Component 3"
                 onSwitchClicked: console.log("User changed checked to: " + checked)


When you run the code you are getting this result:


Native Android with Kotlin

  • We have a total of three files (located in different directories)
  • The code has a total of 96 lines and 1813 characters (without space)

QML Version

  • The complete component resides in one file
  • The code has a total of 41 lines and 594 characters (without space)

The QML version is less than 1/3 ! of the native Android/Kotlin version and offers more functionality. And it is fully reusable for IOS and Windows Applications as well, the style changes automatically. Even more important: The complete code is readable and understandable with a glance. There is no need to check different files.

Leave a Comment