Android UI Essentials: Crafting Stunning & Interactive Interfaces

Android UI Essentials: Crafting Stunning & Interactive Interfaces

Comprehensive Guide to Views, Attributes, and Custom Drawables for Better Android Interfaces

·

19 min read

Introduction to UI in Android

XML - eXtensible Markup Language is a markup language used to create layouts for application screen in Android Development.

Layout defines the structure of the User Interface in our application. Layout in Android is built using a combination of Views and ViewGroup. Layouts contain one and only one Root View Element, that is the parent of all the child Views and ViewGroups.

  • View - a single building block of screen ui : acts as an element, which can display something at the interface or handle an event. Objects of view class are called Widgets

    Example - Text, ImageView, Button, etc.

  • ViewGroup - acts as an invisible container, which gives a layout to the view and

    viewgroups declared under it. Objects of the ViewGroup class are called Layouts

    Example - ListView, GridView, LinearLayout, etc.

    View is a superclass of all the graphical user interface components.

      open class View : Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource
    

    where android.view.ViewGroup is the subclass of View and is the base class for layouts.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

The above layout file consists of LinearLayout as the root element and it holds the TextView and Button element.

XML files are located inside the res/layout/ directory.

During the compilation of the application each XML layout file is compiled into a View resource. Load the layout resource in your app's Activity.onCreate() callback implementation. Do so by calling setContentView(), passing it the reference to your layout resource in the form: R.layout.layout_file_name.

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Attributes

Every View and ViewGroup object has its own variety of XML attributes. Some attributes are specific to a View object. And some are common to all View objects because they are inherited from the root View class, like the id attribute.
Other attributes are layout parameters, which are attributes that describe layout orientations of the View object.

ID

Each View object has an integer ID associated with it, that uniquely identifies that View object. During the app compilation, an integer ID is assigned to the string ID given in the XML format.

<LinearLayout android:id="@+id/my_button" />
/* here @ indicates that it needs to be identified as an ID resource
        + indicates a new resource name that must be created and added
          to the resources in the R.java file.

An ID doesn't need to be unique throughout the entire tree, but it must be unique within the part of the tree you search. It might often be the entire tree, so it's best to make it unique when possible.

Views can be referenced in the application by creating an instance of that View object and capturing it from the layout file.

val addButton: Button = findViewById(R.id.addBtn)
// here addBtn is the ID given in the XML file

Layout Parameters

Define layout parameters for the View that are appropriate for the ViewGroup it resides in. Every ViewGroup class implements a nested class that extends ViewGroup.LayoutParams. This subclass contains property types that define the size and position of each child view based on that ViewGroup.

All view groups include a width and height, using layout_width and layout_height, and each view is required to define them.

You can specify width and height with exact pixel measurement, but more often we use :

  • wrap_content: tells your view to size itself to the dimensions required by its content.

  • match_parent: tells your view to become as big as its parent view group allows.

  • density-independent pixel units (dp)

Padding & Margins

Padding is used to offset the content of the view. However, the margin specifies the extra space the view takes inside the parent.

Padding can be set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight(), and getPaddingBottom().
However, it is more convenient to set them using the XML format.

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical" >
      <TextView android:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="16dp"
                android:padding="8dp"
                android:text="Hello, I am a TextView" />
      <Button android:id="@+id/button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="16dp"
              android:paddingBottom="4dp"
              android:paddingEnd="8dp"
              android:paddingStart="8dp"
              android:paddingTop="4dp"
              android:text="Hello, I am a Button" />
  </LinearLayout>

More XML attributes under View Class

android:alphafloat value: transparency value of view, for code: View.setAlpha(float)
android:autoHandwritingEnabledboolean value: stylus movement within view will trigger handwriting mode, for code: View.setAutoHandwritingEnabled(boolean)
android:autofillHintsdescribes the content of view, for the autofill service to fill appropriate data. eg: password, username, for code: View.setAutofillHints(View.AUTOFILL_HINT_PASSWORD)
android:backgrounddrawable to use as background. for code: View.setBackgroundResource(int)
android:backgroundTintsets tint to apply to background, for code: View.setBackgroundTintList(ColorStateList)
android:clickableboolean value: defines whether this view reacts to click events, for code: View.setClickable(boolean)
android:fadeScrollbarsboolean value: defines whether to fade out scrollbar, when they are not in use, for code: View.setScrollbarFadingEnabled(boolean)
android:longClickableboolean value, defines whether view reacts to long click events, for code: View.setLongClickable(boolean)
android:onClickdefines method to invoke when view clicked, function should be declared in activity
android:visibilityint value, controls visibility of the view, for code: View.setVisibility(int) → 0: visible, 1: invisible, 2:gone

UI → Views

TextView

Android TextView is simply a view that is used to display the text to the user and optionally allows us to modify or edit it. The TextView class inherits from the View class & the ViewTreeObserver class

open class TextView : View, ViewTreeObserver.OnPreDrawListener

TextView inherits all the attributes of View Class & some common XML attributes for TextView are :

  • android:allowUndo controls, whether undo, is allowed to textview or not.

  • android:autoLink converts links to clickable links

  • android:autoText autocorrects the textual input

  • android:capitalize capitalizes the textual input

  • android:digits specifies numeric input to text

  • android:drawableBottom , android:drawableEnd, android:drawableLeft, android:drawableRight, android:drawableStart specifies drawable with the textview

  • android:drawablePadding adds padding to the drawable

  • android:ellipsize causes words that are longer than the view is wide to be ellipsized instead of broken in the middle

  • android:ems makes the TextView be exactly this many ems wide.

  • android:fontFamily specifies the font family for the text

  • android:gravity specifies how to align the text within the view

  • android:hint specifies the hint msg to display when no text

  • android:inputType specifies the input type of the textview

  • android:password makes the characters displayed as a dot

  • android:text specifies the text to display

  • android:textColor android:textColorHighlight android:textColorHint android:textColorLink specify the text color

  • android:textSize android:textStyle specify the text appearance

  • android:scrollHorizontally allow text to be scrolled horizontally

Demonstration of TextView :

<TextView
    android:id="@+id/introText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="100dp"
    android:text="this is an introduction to text views"
    android:paddingLeft="10dp"
    android:fontFamily="@font/sanfro"
    android:textStyle="bold"
    android:textSize="30sp"/>

Gives a margin of 100dp with the top of the layout —— adds a padding of 10dp at the left within the textview —— assigns font family to the textView which is located inside the res/fonts directory named sanfro —— makes the text bold and of 30sp.

<TextView
    android:id="@+id/descText"
    android:layout_width="150dp"
    android:layout_height="150dp"
    android:layout_gravity="center"
    android:layout_marginTop="50dp"
    android:text="multi line text view in android, has some special attributes"
    android:textSize="20sp"
    android:textStyle="italic"
    android:textColor="#ff90"
    android:ellipsize="end"
    android:ems="3"/>

Makes the view come to the centre of the layout —— give a margin of 50dp with the textbox above it —— assign the text size, colour and style

<TextView
    android:id="@+id/textImage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="50dp"
    android:paddingLeft="20dp"
    android:text="text with drawable/image"
    android:textStyle="bold"
    android:textSize="24sp"
    android:drawableRight="@drawable/ic_launcher_background"
    android:drawablePadding="10dp"/>

adds a 50dp margin with the textbox above it —— adds a padding of 20dp to the left within the textbox —— gives text style and size —— adds a drawable file at the right located in the res/drawable directory —— add padding to the drawable within the textview

Demonstration of TextView in the functional Kotlin code :

//import..
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView = findViewById<TextView>(R.id.descText)
//we refer textView variable to the TextView resource with id descText
        val text  = textView.text.toString()
//we get is text and convert it into string using the toString() method
        Log.d("msg: ", text)
//we return that text in the logcat

        val heading = findViewById<TextView>(R.id.introText)
//we refer heading variable to the TextView resource with id introText
        heading.text = "Hi ${10/5}"
//we set the resource text
    }
}

Button

Android Button is a widget that is used to notice interactions and trigger actions in the application. The Button Class extends the TextView class in Kotlin.

open class Button : TextView

Button inherits all the XML attributes of TextView and View class & some common XML attributes are :

  • android:onClick specifies the Kotlin function that is invoked in the activity when the button is clicked

  • android:background sets the background color/drawable on the Button.

Demonstration of Button :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView ... />

    <Button
        android:id="@+id/boldBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="BOLD"
        android:textColor="@color/white"
        android:layout_marginTop="45dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <TextView ... />
</androidx.constraintlayout.widget.ConstraintLayout>

Here our Root View is the constraint layout, that enables us to define layouts based on constraints to other layouts.

Demonstration of Button in the functional Kotlin code :

  • setOnClickListener - triggers when a button is clicked.

  • setOnLongClickListner - triggers when a button is pressed for a longer duration. requires an ending false boolean value to trigger. if true, doesn't trigger.

The curly brackets following the two click listeners are lambda expressions.

//import..
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val boldButton = findViewById<Button>(R.id.boldBtn)
        val textbox = findViewById<TextView>(R.id.textView)

        boldButton.setOnClickListener{ //sets the text to bold
            textbox.setTypeface(null, Typeface.BOLD)
        }
        boldButton.setOnLongClickListener{ //changes the text
            textbox.text = "Bye!"
            false //trigger the LongClickListener
        }
    }
}

EditText

Android EditText is a user interface control that allows the user to enter or modify the text. The EditText class inherits from the TextView Class.

open class EditText : TextView

EditText inherits all the XML attributes of TextView and View class & some common attributes of EditText are :

  • android:inputType specifies the input type required. date, text, number. etc.

Demonstration of EditText :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/usernameET"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:hint="Username"
        android:inputType="text"
        android:layout_marginTop="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button ... />

</androidx.constraintlayout.widget.ConstraintLayout>

Here our Root Element in Constraint Layout, which has an EditText and a Button. The EditText has a text input type and a hint for the user to input a username.

Demonstration of EditText in the functional Kotlin code :

//import..
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val inputUsername = findViewById<EditText>(R.id.usernameET)
        val btn = findViewById<Button>(R.id.btn)

        btn.setOnClickListener{
            val username = inputUsername.text.toString()
//storing the input in the username variable
            Log.d("Username: ", username)
//displaying the username value in the logcat
        }
    }
}

ImageView

Android ImageView is a user interface control that is used to display any type of image resource in the application. ImageView class is a direct subclass of the Kotlin View Class

open class ImageView : View

Some common XML attributes for ImageView are :

  • android:adjustViewBounds adjust the bounds of the drawable to maintain its aspect ratio

  • android:cropToPadding crops the image to fit within the padding

  • android:maxHeight gives a maximum height to the View

  • android:maxWidth gives a maximum width to the View

  • android:scaleType specifies how the image should be resized or moved to match the view's size. Values include center, centerCrop, fitCenter, etc.

  • android:src specifies the drawable to set in the view

  • android:tint sets the tinting color of the image

Demonstration of ImageView :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/black"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:tint="@color/white" />

    <Button ... />

</androidx.constraintlayout.widget.ConstraintLayout>

Here the Root Element is a Constraint Layout which has an ImageView and a Button. The ImageView has a default image named ic_launcher_foreground in the res/drawable directory.

Demonstration of ImageView in the functional Kotlin code :

//import..
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val image = findViewById<ImageView>(R.id.imageView)
        val btn = findViewById<Button>(R.id.changeBtn)

        btn.setOnClickListener{
            image.setImageResource(R.drawable.person)
//image resource should be stored in drawable folder
//change image resource of imageview to R.drawable.person on button click
        }
    }
}

ImageButton

Android ImageButton is a widget that is used to display a button having an image. The ImageButton class inherits from the ImageView class

open class ImageButton : ImageView

ImageButton works exactly like a android.widget.Button, and the image on the button is added using android:src attribute or the setImageResource(int) method.

ImageButton inherits all the XML attributes of ImageView and View class

💡
Checkout how to make Custom Views using drawables in the later part of this article.

CardView

CardView is a versatile widget provided by Android that is used to create a container with multiple views.

Some common XML attributes for CardView are :

app:cardCornerRadius Sets the corner radius of the card.
app:cardElevation Sets the shadow elevation of the card.
app:cardBackgroundColor Changes the card’s background color.
app:cardUseCompatPadding Ensures consistent padding for the card across devices.
app:cardPreventCornerOverlap Prevents overlapping content from going outside the rounded corners.

Demonstration of CardView :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    //statements>
    <androidx.cardview.widget.CardView
        android:layout_width="200dp"
        android:layout_height="300dp"
        app:cardCornerRadius="20dp"
        app:cardElevation="20dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView ../>
            <TextView ../>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>

Demonstration of CardView in functional Kotlin code :

val cardView = findViewById<CardView>(R.id.cardView)
cardView.setOnClickListener {
    Toast.makeText(this, "Card clicked!", Toast.LENGTH_SHORT).show()
}

CheckBox

Android CheckBox is a common widget that works as a Button and has two states, checked & unchecked. The CheckBox class inherits from the CompoundButton class which is further inherited from the Button class

open class CheckBox : CompoundButton

CheckBox inherits all the XML attributes of TextView,View, Button & Compound Button class & some common attributes of CompoundButton are :

  • android:checked which specifies the initial checked state of the button

Demonstration of Checkbox :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView ... />
    <CheckBox
        android:id="@+id/pannerCheck"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Panner"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="-270dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />
    <CheckBox
        android:id="@+id/cheeseCheck" .. />
    <CheckBox
        android:id="@+id/mushCheck" ..  />

</androidx.constraintlayout.widget.ConstraintLayout>

Here we define 3 Checkbox under our Root View Element.

Demonstration of CheckBox in the functional Kotlin code :

//import..
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val panner = findViewById<CheckBox>(R.id.pannerCheck)
        val cheese = findViewById<CheckBox>(R.id.cheeseCheck)
        val mushroom = findViewById<CheckBox>(R.id.mushCheck)

        panner.setOnCheckedChangeListener{ _, isChecked ->
            val text = "You want the following toppings: " + (if (isChecked) "Panner" else "") + (if (cheese.isChecked) "Cheese" else "") + (if (mushroom.isChecked) "Mushroom" else "")
            Log.d("Order: ", text)
        }
//following method is called when the state of the checkbox is changed
//where _ represents the compound button whose state is changed
//isChecked returns the state as a boolean value
//followed by a lambda expression 
        cheese.setOnCheckedChangeListener{ _, isChecked ->
            val text = "You want the following toppings: " + (if (panner.isChecked) "Panner" else "") + (if (isChecked) "Cheese" else "") + (if (mushroom.isChecked) "Mushroom" else "")
            Log.d("Order: ", text)
        }
        mushroom.setOnCheckedChangeListener{ _, isChecked ->
            val text = "You want the following toppings: " + (if (panner.isChecked) "Panner" else "") + (if (cheese.isChecked) "Cheese" else "") + (if (isChecked) "Mushroom" else "")
            Log.d("Order: ", text)
        }
    }
}

ToggleButton

Android, ToggleButton is just like a switch containing two states either ON or OFF, unlike switch, it doesn't have a slider. The ToggleButton class inherits from the CompoundButton class which is further inherited from the Button class

open class ToggleButton : CompoundButton

ToggleButton inherits all the XML attributes of TextView,View, Button & Compound Button class & some common attributes of ToggleButton are :

  • android:textOff specifies text when the button is off

  • android:textOn specifies text when the button is on

  • android:disabledAlpha specifies the alpha to apply to the indicator when disabled.

Demonstration of ToggleButton :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ToggleButton
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOff="Off"
        android:textOn="On"
        android:textSize="32sp"
        android:disabledAlpha="0.5"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Demonstration of ToggleButton in the functional Kotlin code :

import android.os.Bundle
import android.util.Log
import android.widget.ToggleButton

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val btn = findViewById<ToggleButton>(R.id.btn)
        btn.setChecked(true)
        btn.setOnCheckedChangeListener{ _, isChecked ->
            Log.d("Status:","You turned it" + (if (isChecked) "On" else "Off"))
        }
    }
}

Switch

Similar to the Toggle Button, but this one is from the Material Components Library.

open class SwitchMaterial : CompoundButton

Some common XML attributes for Switch are :

android:checked Defines the initial state (on/off).
app:thumbColor Sets the color of the thumb (toggle).
app:trackColor Sets the color of the track.
app:useMaterialThemeColors If set to true, applies the Material theme colors automatically.

Demonstration of Switch :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">
    <com.google.android.material.switchmaterial.SwitchMaterial
        android:id="@+id/material_switch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/material_switch"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Demonstration of Switch in functional Kotlin code :

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: SwitchLayoutBinding = SwitchLayoutBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.materialSwitch.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked)// The switch is checked.
            else // The switch isn't checked.
        }
    }
}

Seek-bar

Widget that allows users to select a value from a continuous or discrete range by dragging a thumb (slider).

Some common XML attributes for Seek-bar are :

android:max Sets the maximum value of the SeekBar.
android:progress Sets the current progress (default position of the thumb).
android:thumb Defines a custom drawable for the slider's thumb.
android:secondaryProgress Sets a secondary progress bar (useful for buffered progress in streaming apps).

Demonstration of Seek-bar :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ..>
    <SeekBar
        android:id="@+id/seekbar"
        android:max="100"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView .. />
</androidx.constraintlayout.widget.ConstraintLayout>

Demonstration of Seek-bar in functional Kotlin code:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        //statements..
        val seekBar = findViewById<SeekBar>(R.id.seekbar)
        val textView = findViewById<TextView>(R.id.textView)
        seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                textView.text = "Progress: " + p1.toString()
            }
            override fun onStartTrackingTouch(p0: SeekBar?) {
                //statments
            }
            override fun onStopTrackingTouch(p0: SeekBar?) {
                textView.text = "selected ${p0?.progress}"
            }
        })
    }
}

Adding Custom Drawable to Seek-bar :

seekbar_thumb.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
  <stroke android:color="#CDDC39"
      android:width="4dp"/>
    <solid android:color="@color/black"/>
    <size android:height="24dp" android:width="24dp"/>
</shape>
seekbar_line.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:gravity="center_vertical">
        <shape android:shape="rectangle">
            <solid android:color="#605A5C"/>
            <size android:height="5dp"/>
        </shape>
    </item>
</layer-list>
Adding to Seekbar View in XML : 

<Seekbar
    ...
    android:thumb="@drawable/seekbar_thumb"
    android:progressDrawable="@drawable/custom_seekbar">
</Seekbar>

Spinner

Android Spinner is used to create a drop-down list on the screen. The spinner is loaded with data using an Adapter. The adapter sets the data as well as the layout for the items to be loaded in the Spinner. The spinner class inherits from the AbsSpinner and DialogInterface.OnClickListener class

open class Spinner : AbsSpinner, DialogInterface.OnClickListener

Some common XML attributes for Spinner are :

  • android:entries which specifies the entries of the spinners dialog, if the entries are stored in the strings.xml file from the res/values directory

  • android:popupBackground which specifies the background drawable for the dropdown popup

  • android:prompt which specifies the prompt to display when the spinner dialog is shown

  • android:spinnerMode which specifies the display mode for spinner options(dialog, or dropdown)

Demonstration of Spinner :

Ways of linking data to the Spinners dialog :

<resources>
    <string name="app_name">spinner</string>
    <string-array name="gender">
        <item>Male</item>
        <item>Female</item>
    </string-array>
</resources>

adding data items to the strings.xml file in the res/values directory, in the form of a string array.

This string array can be linked to the spinner using the XML attribute :

<Spinner .. android:entries="@array/gender" .. />

Or in the Kotlin code file using the Adapter :

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) { //statements.. 
        val spinner = findViewById<Spinner>(R.id.spinner)
        val valuesGender = resources.getStringArray(R.array.gender)
//specify variable to our string array resource using 
//resources.getStringArray(int) method

        val adapter = ArrayAdapter( this, android.R.layout.simple_spinner_item, valuesGender)
        spinner.adapter = adapter
        }
    }
}

The data can also be linked directly from the Kotlin Code file by creating an array or list object and specifying the adapter and spinner all in the same block :

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) { //statements.. 
        val spinner = findViewById<Spinner>(R.id.spinner)
        val genderList = listOf("Male","Female")
        val adapter = ArrayAdapter<String>(this, 
        com.google.android.material.R.layout.support_simple_spinner_dropdown_item, genderList)
        spinner.adapter = adapter
    }
}

Demonstration of Spinner in the functional Kotlin code :

When the user selects an item from the spinner's menu, the Spinner object receives an on-item-selected event. To define the selection event handler for a spinner, we need to implement the AdapterView.OnItemSelectedListener interface and the corresponding onItemSelected() callback method.

spinner.onItemSelectedListener = object :AdapterView.OnItemSelectedListener{
    override fun onItemSelected(adapter: AdapterView<*>?, view: View?, position: Int, id: Long) {
// An item is selected. You can retrieve the selected item using
// adapter.getItemAtPosition(position).
// position specifies the index of the data selected
         Toast.makeText(this@MainActivity, 
         "You selected ${adapter?.getItemAtPosition(position).toString()}",
         Toast.LENGTH_SHORT).show()
//here we need to specify this@MainActivity - as we are inside an anonymous class
    }
    override fun onNothingSelected(adapter: AdapterView<*>?) { } 
}

RadioButton & RadioGroup

Android Radio buttons let the user select one option from a set of mutually exclusive options. Because radio buttons are mutually exclusive, group them inside a RadioGroup widget i.e. android.widget.RadioGroup. RadioGroup ensures that only one radio button within a group can be selected at a time.
The RadioButton class inherits from the CompoundButton class which is further inherited from the Button class

open class RadioButton : CompoundButton

When several radio buttons live inside a radio group, checking one radio button unchecks all the others.

RadioButton inherits all the XML attributes of TextView,View, Button & Compound Button class

The RadioGroup inherits from the LinearLayout class

open class RadioGroup : LinearLayout

RadioGroup inherits all the XML attributes of ViewGroup, View & LinearLayout class & some common attributes of RadioGroup are :

  • android:orientation specifies the orientation of the child radio buttons

  • android:checkedButton specifies the default checked radio button

Demonstration of RadioButton & RadioGroup :

<androidx.constraintlayout.widget.ConstraintLayout ..>
    <RadioGroup
        android:id="@+id/btnHead"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#dbeceb" .. 
        <TextView .. />
        <RadioButton
            android:id="@+id/wish1btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="10dp"
            android:paddingLeft="5sp"
            android:text="Wish 1"
            android:textSize="22sp"
            android:textStyle="bold" />
        <RadioButton .. />
        <RadioButton .. />
        <Button .. />
    </RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>

Demonstration of RadioButton & RadioGroup in the functional Kotlin code :

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) { //statements..
        val submit = findViewById<Button>(R.id.submitBtn)
        val radioGroupWish = findViewById<RadioGroup>(R.id.btnHead)

//getting radio group selected status and text using button click event
        submit.setOnClickListener{
            val checkedButtonID = radioGroupWish.checkedRadioButtonId 
//radioGroup.checkedRadioButtonID returns the ID of the radiobutton checked
            val checkedButton = findViewById<RadioButton>(checkedButtonID)
            Log.d("Order: ",checkedButton.text.toString())
        }
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) { //statements..
        val radioGroupWish = findViewById<RadioGroup>(R.id.btnHead)

//getting radio group selected item using on checked change listener 
        radioGroupWish.setOnCheckedChangeListener(
            RadioGroup.OnCheckedChangeListener { _, checkedId ->
                val checkedBtn =  findViewById<RadioButton>(checkedId)
                Log.d("Order: ",checkedBtn.text.toString())
            })
    }
}

Custom Drawables for Views

Drawables in Android are graphics resources used to define backgrounds, shapes, state-based icons, or other visual elements for UI components. They are stored in the res/drawable directory and can be created using XML or images.

Types of Drawables for Custom Views

  1. Shape Drawable (shape)

    • Used to create custom buttons, backgrounds, and borders.

    • Can define solid colors, gradients, strokes, corners, and padding.

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="12dp"/>
        <solid android:color="@color/blue"/>
        <stroke android:width="2dp" android:color="@color/dark_blue"/>
        <padding android:left="10dp" android:right="10dp"/>
    </shape>
  1. State List Drawable (selector)

    • Allows different appearances based on user interaction (e.g., pressed, focused, disabled).

    • Used for buttons, text fields, or list items.

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true" android:drawable="@color/dark_blue"/>
        <item android:drawable="@color/blue"/>
    </selector>
  1. Gradient Drawable

    • Creates linear, radial, or sweep gradients as backgrounds.

    • Commonly used for app backgrounds and buttons.

    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <gradient android:startColor="#FF5733" android:endColor="#C70039"
            android:angle="270"/>
    </shape>
  1. Layer-List Drawable

  2. Inset Drawable

  3. Clip Drawable

  4. Vector Drawables