XML Layouts & Views

Android Development Fundamentals
Course 1 ยท Chapter 3 ยท XML Layouts & Views

๐Ÿ“ XML Layouts & Views

Every screen's visual structure is described in XML, not code โ€” conceptually close to HTML describing a page's structure while CSS handles positioning. This chapter covers the two layout containers used constantly (LinearLayout and ConstraintLayout), the common building-block Views, and view binding โ€” the type-safe way to reach a View from Kotlin, replacing the raw findViewById calls used last chapter.

๐Ÿ“„ XML Layout Basics

<?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:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </LinearLayout>

Every View needs layout_width and layout_height โ€” usually match_parent (fill the available space, like CSS width: 100%) or wrap_content (only as big as the content needs, like CSS's default inline sizing). There's no XML equivalent of a raw pixel value being the norm the way it might be in a quick HTML mockup โ€” Android strongly prefers these two content-relative modes, or explicit dp (density-independent pixel) values from a dimens resource for anything else.

๐Ÿ“ LinearLayout โ€” Stack in One Direction

LinearLayout arranges children in a single row or column, controlled by orientation โ€” directly analogous to a CSS flexbox container locked to one direction:

<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Cancel" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Confirm" /> </LinearLayout>

layout_weight distributes remaining space proportionally among children โ€” the pattern layout_width="0dp" + a weight is the standard idiom for "split the available width," directly equivalent to giving several CSS flex items flex: 1 and width: 0.

๐Ÿ”— ConstraintLayout โ€” Relative Positioning at Scale

ConstraintLayout positions each child relative to the parent or to other children, using explicit constraints on each edge โ€” the default root layout for new activities, because it avoids deeply nested LinearLayouts inside LinearLayouts for anything beyond a simple stack:

<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Welcome" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <Button android:id="@+id/continueButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Continue" app:layout_constraintTop_toBottomOf="@id/title" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>

app:layout_constraintTop_toBottomOf="@id/title" reads naturally: this View's top edge attaches below title's bottom edge. Every child needs both a horizontal constraint (start/end) and a vertical constraint (top/bottom) or its position is undefined โ€” the layout editor's visual designer (Chapter 1's Editor panel) makes dragging these connections considerably faster than hand-writing them.

Android Layouts vs CSS

CSS ConceptAndroid Equivalent
display: flex; flex-direction: column;LinearLayout, orientation="vertical"
flex: 1layout_weight="1" (with layout_width="0dp")
width: 100%layout_width="match_parent"
width: auto (content-sized)layout_width="wrap_content"
CSS Grid / relative anchoringConstraintLayout constraints

๐Ÿงฑ Common Views โ€” A Quick Reference

TextView

Displays text โ€” Android's <p>/<span>. Set via android:text, styled via textSize, textColor.

Button

A tappable button. Click handling is covered fully in Chapter 4, but the View itself is declared the same way as any other.

EditText

A text input field โ€” Android's <input type="text">. inputType controls the keyboard shown (e.g. "number", "textEmailAddress").

ImageView

Displays an image, from a drawable resource (android:src="@drawable/logo") or set at runtime from code.

๐Ÿ”’ View Binding โ€” Type-Safe View References

Chapter 2's findViewById<Button>(R.id.clickButton) works, but has two real problems: it's unchecked at compile time (a typo'd ID or wrong type only fails at runtime), and it's verbose to repeat for every View. View binding fixes both by generating a typed binding class from each layout file automatically.

First, enable it in app/build.gradle.kts:

android { // ...existing config... buildFeatures { viewBinding = true } }

For a layout file activity_main.xml, Android generates a class called ActivityMainBinding with a property for every View that has an android:id:

class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // binding.root replaces the old R.layout.activity_main reference binding.clickButton.setOnClickListener { // typed, autocompleted, and compile-checked binding.titleText.text = "Clicked!" } } }

findViewById vs View Binding

findViewByIdView Binding
Type safetyManual cast, wrong-type crashes at runtimeCompiler-checked, correct type generated
Typo'd IDCompiles, crashes at runtime (returns null / ClassCastException)Won't compile โ€” the property simply doesn't exist
RepetitionOne call per View, every time it's neededOne binding.inflate() call, then binding.viewName everywhere
โš  lateinit var โ€” A Kotlin Reminder

lateinit var binding: ActivityMainBinding is necessary because binding genuinely can't be initialized where it's declared (it needs layoutInflater, only available once the Activity exists) โ€” but it's guaranteed to be set before any code that uses it actually runs, in onCreate. This is exactly the kind of case Kotlin's lateinit exists for: a non-nullable var that's set once, shortly after construction, not immediately at declaration.

๐Ÿ’ป Coding Challenges

Challenge 1: A LinearLayout Form

Build a vertical LinearLayout containing a TextView (label), an EditText (input), and a Button, each with sensible layout_width/layout_height. Give the EditText an appropriate inputType for a name field.

Goal: Practice basic LinearLayout structure and common View attributes.

โ†’ Solution

Challenge 2: A ConstraintLayout Screen

Rebuild the same three Views (label, input, button) from Challenge 1 using ConstraintLayout instead โ€” the label at the top, the input below it, and the button below that, all with correct top/start/end constraints so the layout works regardless of screen width.

Goal: Practice writing explicit ConstraintLayout constraints by hand.

โ†’ Solution

Challenge 3: Migrate to View Binding

Enable viewBinding in build.gradle.kts, then rewrite MainActivity from Challenge 2 (or Chapter 2) to use view binding instead of any findViewById calls โ€” set the button's click listener to update the TextView's text using binding.viewName syntax throughout.

Goal: Practice the full view binding setup and usage, end to end.

โ†’ Solution

๐Ÿ’ก ConstraintLayout Feels Unfamiliar Before It Feels Natural

Coming from CSS, writing explicit constraints for every single edge feels tedious at first compared to flexbox's implicit flow. The payoff shows up once layouts get more complex โ€” a ConstraintLayout with 15 Views stays a single flat hierarchy, where the equivalent nested-LinearLayout version would be five or six layers deep and considerably harder to reason about or restyle.

๐ŸŽฏ What's Next

Next chapter: User Interaction โ€” onClick, event listeners, Intents (explicit/implicit), and passing data between screens.