Button trong SwiftUI
1. Button cơ bản
Button("Tap Me") {
print("Button tapped!")
}
// Action riêng
Button(action: {
print("Action executed")
}) {
Text("Click Here")
}2. Button với Label
Button {
// Action
} label: {
Label("Add to Cart", systemImage: "cart.badge.plus")
}
Button {
// Action
} label: {
HStack {
Image(systemName: "heart.fill")
Text("Like")
}
}3. Button Styles
Built-in Styles
Button("Default") { }
Button("Bordered") { }
.buttonStyle(.bordered)
Button("Bordered Prominent") { }
.buttonStyle(.borderedProminent)
Button("Borderless") { }
.buttonStyle(.borderless)
Button("Plain") { }
.buttonStyle(.plain)Tint Color
Button("Green Button") { }
.buttonStyle(.borderedProminent)
.tint(.green)
Button("Red Button") { }
.buttonStyle(.bordered)
.tint(.red)4. Custom Button Style
struct PrimaryButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.frame(maxWidth: .infinity)
.background(configuration.isPressed ? .blue.opacity(0.8) : .blue)
.foregroundColor(.white)
.cornerRadius(12)
.scaleEffect(configuration.isPressed ? 0.95 : 1.0)
}
}
// Sử dụng
Button("Login") { }
.buttonStyle(PrimaryButtonStyle())5. Custom Styled Buttons
// Pill Button
Button {
// Action
} label: {
Text("Subscribe")
.fontWeight(.semibold)
.padding(.horizontal, 24)
.padding(.vertical, 12)
.background(.blue)
.foregroundColor(.white)
.clipShape(Capsule())
}
// Icon Button
Button {
// Action
} label: {
Image(systemName: "plus")
.font(.title2)
.foregroundColor(.white)
.frame(width: 56, height: 56)
.background(.blue)
.clipShape(Circle())
.shadow(radius: 4)
}
// Outline Button
Button {
// Action
} label: {
Text("Cancel")
.padding()
.frame(maxWidth: .infinity)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(.blue, lineWidth: 2)
)
}6. Button với State
struct ContentView: View {
@State private var count = 0
@State private var isLoading = false
var body: some View {
VStack(spacing: 20) {
// Counter
HStack {
Button("-") { count -= 1 }
.buttonStyle(.bordered)
Text("\(count)")
.font(.title)
.frame(width: 50)
Button("+") { count += 1 }
.buttonStyle(.bordered)
}
// Loading button
Button {
isLoading = true
// Simulate async operation
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
isLoading = false
}
} label: {
if isLoading {
ProgressView()
} else {
Text("Submit")
}
}
.buttonStyle(.borderedProminent)
.disabled(isLoading)
}
}
}7. Button Roles
// Destructive role
Button("Delete", role: .destructive) {
// Delete action
}
// Cancel role
Button("Cancel", role: .cancel) {
// Cancel action
}
// Trong Alert
.alert("Delete?", isPresented: $showAlert) {
Button("Delete", role: .destructive) { }
Button("Cancel", role: .cancel) { }
}8. Disabled State
struct FormView: View {
@State private var email = ""
var isValid: Bool {
email.contains("@")
}
var body: some View {
VStack {
TextField("Email", text: $email)
.textFieldStyle(.roundedBorder)
Button("Submit") {
// Submit
}
.buttonStyle(.borderedProminent)
.disabled(!isValid)
}
.padding()
}
}9. NavigationLink vs Button
// Navigation
NavigationStack {
NavigationLink("Go to Detail") {
DetailView()
}
.buttonStyle(.borderedProminent)
}
// Button với navigation
struct ContentView: View {
@State private var showDetail = false
var body: some View {
NavigationStack {
Button("Show Detail") {
showDetail = true
}
.navigationDestination(isPresented: $showDetail) {
DetailView()
}
}
}
}📝 Tóm tắt
| Style | Appearance |
|---|---|
.automatic | Mặc định |
.bordered | Viền nhẹ |
.borderedProminent | Nền màu primary |
.borderless | Không viền |
.plain | Text thuần |
Key modifiers: .buttonStyle(), .tint(), .disabled(), .role()
Last updated on