Building XML-Based UI for Beginners

In the realm of Android development, XML has been a cornerstone for crafting user interfaces (UIs). Even with the rise of modern UI toolkits like Jetpack Compose, a solid understanding of XML-based UIs remains valuable, particularly for maintaining legacy projects or integrating with specific libraries. This post provides a beginner-friendly guide to building XML-based UIs in Android.

Why XML-Based UIs?

Although Jetpack Compose offers a modern approach, XML-based UIs continue to be relevant because:

  • Legacy Codebase: Many existing Android applications use XML layouts.
  • Interoperability: XML views can be integrated into Compose-based apps.
  • Simplicity for Basic Layouts: XML can be straightforward for simple UI designs.
  • Tooling Support: Android Studio provides excellent tooling for designing and previewing XML layouts.

Setting Up Your Development Environment

To get started with XML-based UIs, ensure you have:

  1. Android Studio: Download and install the latest version of Android Studio from the official website.
  2. SDK: Configure the Android SDK (Software Development Kit) through Android Studio’s SDK Manager.
  3. Emulator/Device: Set up an Android emulator or connect a physical Android device for testing.

Understanding XML Layout Structure

Android XML layouts are defined in XML files, typically located in the res/layout directory of your project. A basic XML layout consists of a root element, which is usually a ViewGroup, and various child View elements.

Basic Layout Example


<?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/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, Android!"
        android:textSize="20sp"
        android:textColor="#000000"/>

</LinearLayout>
  • <LinearLayout>: A ViewGroup that arranges its children in a single direction (horizontally or vertically).
  • <TextView>: A View that displays text.
  • android:layout_width, android:layout_height: Attributes that define the width and height of the view.
  • android:id: A unique identifier for the view.
  • android:text: The text to display in the TextView.
  • android:textSize: The size of the text.
  • android:textColor: The color of the text.

Common Layout Types

Android offers several layout types, each serving different purposes:

1. LinearLayout

Arranges views in a single row or column. Useful for simple, linear arrangements.


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 2"/>

</LinearLayout>

2. RelativeLayout

Arranges views relative to each other or the parent layout. Provides flexibility for complex designs.


<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Top Left"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"/>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bottom Right"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"/>

</RelativeLayout>

3. ConstraintLayout

Arranges views using constraints relative to each other, the parent layout, or guidelines. Recommended for complex and responsive UIs.


<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">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, ConstraintLayout!"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

4. FrameLayout

A placeholder on the screen that you can use to display a single view. Commonly used for swapping views.


<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is in a FrameLayout"/>

</FrameLayout>

5. ScrollView

Allows you to scroll content that is larger than the screen.


<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Content..."/>
        <!-- Add more content here -->

    </LinearLayout>

</ScrollView>

Common UI Elements

Besides TextView and Button, Android offers a rich set of UI elements:

  • EditText: Allows users to input text.
  • ImageView: Displays images.
  • CheckBox: A checkable item.
  • RadioButton: Part of a radio group; only one can be selected.
  • ProgressBar: Indicates the progress of an operation.
  • RecyclerView: A flexible view for providing a limited window into a large data set.

Example: Using EditText


<EditText
    android:id="@+id/editText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter text here"/>

Example: Using ImageView


<ImageView
    android:id="@+id/imageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher_background"/>

Attributes and Properties

Each UI element has attributes that define its properties. Common attributes include:

  • android:layout_width, android:layout_height: Defines the size of the view. Values can be wrap_content, match_parent, or a specific dimension (e.g., 100dp).
  • android:id: A unique identifier to reference the view in your code.
  • android:text: Text displayed in a TextView or button.
  • android:hint: Placeholder text in an EditText.
  • android:src: Source of an image in an ImageView.
  • android:padding, android:margin: Defines the spacing around the content and view, respectively.
  • android:visibility: Determines whether the view is visible (visible, invisible, gone).

Example: Setting Padding and Margin


<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello, Padding and Margin!"
    android:padding="20dp"
    android:margin="10dp"/>

Connecting XML Layout to Activity/Fragment

To display your XML layout in an Activity or Fragment, you need to inflate the layout in your code.

Activity Example


import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.R  // Replace with your app's package name

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

In the onCreate method, setContentView(R.layout.activity_main) inflates the XML layout file named activity_main.xml and sets it as the content view for the Activity.

Accessing UI Elements in Code

To interact with UI elements defined in the XML layout, you can access them using their IDs.


import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.R  // Replace with your app's package name

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

        // Access the TextView using its ID
        val textView: TextView = findViewById(R.id.textView)

        // Modify the TextView
        textView.text = "Hello, from Kotlin!"
    }
}

Best Practices

  • Use ConstraintLayout: For complex layouts, prefer ConstraintLayout for better performance and responsiveness.
  • Keep Layouts Simple: Avoid deeply nested layouts to maintain performance.
  • Use IDs Wisely: Assign meaningful IDs to UI elements you need to access in code.
  • Optimize for Different Screen Sizes: Use dimension resources (dimens.xml) to define sizes that adapt to different screen sizes.
  • Use Styles and Themes: Define common attributes in styles and themes to maintain consistency across your app.

Example: Creating a Login Screen

Let’s create a simple login screen using XML.

activity_login.xml


<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">

    <TextView
        android:id="@+id/loginTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login"
        android:textSize="24sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="32dp"/>

    <EditText
        android:id="@+id/usernameEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Username"
        android:inputType="textEmailAddress"
        app:layout_constraintTop_toBottomOf="@+id/loginTitle"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"/>

    <EditText
        android:id="@+id/passwordEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Password"
        android:inputType="textPassword"
        app:layout_constraintTop_toBottomOf="@+id/usernameEditText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="8dp"/>

    <Button
        android:id="@+id/loginButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login"
        app:layout_constraintTop_toBottomOf="@+id/passwordEditText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

LoginActivity.kt


import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.R

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

        val usernameEditText: EditText = findViewById(R.id.usernameEditText)
        val passwordEditText: EditText = findViewById(R.id.passwordEditText)
        val loginButton: Button = findViewById(R.id.loginButton)

        loginButton.setOnClickListener {
            val username = usernameEditText.text.toString()
            val password = passwordEditText.text.toString()

            // Validate credentials
            if (username == "admin" && password == "password") {
                Toast.makeText(this, "Login successful!", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Invalid credentials", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

Conclusion

Building XML-based UIs is a fundamental skill for Android developers. While newer technologies like Jetpack Compose offer more modern approaches, understanding XML layouts is essential for working with legacy projects, integrating existing components, and grasping the underlying principles of Android UI development. By mastering XML layouts, you’ll be well-equipped to tackle a wide range of Android development challenges.