Text, Image, Button, TextField
SwiftUI gives you ready-made views for the basics. Text shows strings, Image displays pictures, Button handles taps, and TextField collects user input. Each one is a struct that conforms to the View protocol.
VStack(spacing: 16) {
Text("Hello SwiftUI!")
.font(.title)
Image(systemName: "star.fill")
.foregroundColor(.yellow)
.font(.largeTitle)
Button("Press Me") {
print("Button tapped!")
}
.buttonStyle(.borderedProminent)
TextField("Enter your name", text: $username)
.textFieldStyle(.roundedBorder)
}
Try it Yourself ->
Modifier Chaining
Modifiers change how a view looks or behaves. Chain them one after another — order matters. A padding before a background looks different from a background before a padding. Think of modifiers as layers stacked on top of each other.
Text("Styled Text")
.font(.title2)
.fontWeight(.semibold)
.foregroundColor(.white)
.padding()
.background(Color.blue)
.cornerRadius(10)
.shadow(color: .blue.opacity(0.3), radius: 5, x: 0, y: 3)
Try it Yourself ->
ViewBuilder for Composing Views
When a function or closure needs to return multiple views, use @ViewBuilder. It lets you write several views side by side and SwiftUI combines them into one. This is how VStack, HStack, and Button work internally.
@ViewBuilder
func makeHeader() -> some View {
Text("Welcome!")
.font(.largeTitle)
Text("Glad you're here.")
.font(.subheadline)
.foregroundColor(.secondary)
}
struct HeaderView: View {
var body: some View {
VStack(alignment: .leading, spacing: 8) {
makeHeader()
}
}
}
Try it Yourself ->
Custom Views with View Protocol
Build your own reusable views by creating a struct that conforms to View. Give it a body property and you're done. Break complex UIs into small, testable pieces.
struct ProfileBadge: View {
let name: String
let avatar: String
var body: some View {
HStack(spacing: 12) {
Image(systemName: avatar)
.font(.title)
.foregroundColor(.white)
.frame(width: 50, height: 50)
.background(Color.green)
.clipShape(Circle())
Text(name)
.font(.headline)
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(12)
}
}
struct ContentView: View {
var body: some View {
ProfileBadge(name: "Alice", avatar: "person.circle.fill")
}
}
Try it Yourself ->
@State for Mutable View Data
Views in SwiftUI are structs — they can't change their own properties directly. Use @State to give a view its own mutable state. When @State changes, SwiftUI redraws the view automatically.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 20) {
Text("Count: \(count)")
.font(.title)
HStack(spacing: 16) {
Button("-") { count -= 1 }
.buttonStyle(.bordered)
Button("+") { count += 1 }
.buttonStyle(.borderedProminent)
}
}
}
}
Try it Yourself ->