XML Layouts & Views
๐ XML Layouts & Views
๐ XML Layout Basics
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:
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:
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 Concept | Android Equivalent |
|---|---|
| display: flex; flex-direction: column; | LinearLayout, orientation="vertical" |
| flex: 1 | layout_weight="1" (with layout_width="0dp") |
| width: 100% | layout_width="match_parent" |
| width: auto (content-sized) | layout_width="wrap_content" |
| CSS Grid / relative anchoring | ConstraintLayout 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:
For a layout file activity_main.xml, Android generates a class called ActivityMainBinding with a property for every View that has an android:id:
findViewById vs View Binding
| findViewById | View Binding | |
|---|---|---|
| Type safety | Manual cast, wrong-type crashes at runtime | Compiler-checked, correct type generated |
| Typo'd ID | Compiles, crashes at runtime (returns null / ClassCastException) | Won't compile โ the property simply doesn't exist |
| Repetition | One call per View, every time it's needed | One binding.inflate() call, then binding.viewName everywhere |
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.
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.
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.
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.