@Binding
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”@Binding tạo two-way connection giữa parent và child view.
struct ParentView: View { @State private var isOn = false
var body: some View { ChildView(isOn: $isOn) // Pass binding }}
struct ChildView: View { @Binding var isOn: Bool // Receive binding
var body: some View { Toggle("Toggle", isOn: $isOn) }}2. Cách hoạt động
Phần tiêu đề “2. Cách hoạt động”flowchart TD P["📱 ParentView (@State)"] -->|"$isOn (Binding)"| C["📦 ChildView (@Binding)"] C -->|"thay đổi"| P2["🔄 ParentView updated"]
style P fill:#e3f2fd,stroke:#2196f3 style C fill:#fff3e0,stroke:#ff9800 style P2 fill:#e8f5e9,stroke:#4caf503. Ví dụ thực tế
Phần tiêu đề “3. Ví dụ thực tế”Custom Toggle
Phần tiêu đề “Custom Toggle”struct CustomToggle: View { @Binding var isOn: Bool
var body: some View { Button { isOn.toggle() } label: { Image(systemName: isOn ? "checkmark.circle.fill" : "circle") .foregroundColor(isOn ? .green : .gray) .font(.title) } }}
// Usagestruct ContentView: View { @State private var option1 = false @State private var option2 = true
var body: some View { VStack { HStack { Text("Option 1") Spacer() CustomToggle(isOn: $option1) }
HStack { Text("Option 2") Spacer() CustomToggle(isOn: $option2) } } .padding() }}Rating View
Phần tiêu đề “Rating View”struct RatingView: View { @Binding var rating: Int let maxRating: Int = 5
var body: some View { HStack { ForEach(1...maxRating, id: \.self) { star in Image(systemName: star <= rating ? "star.fill" : "star") .foregroundColor(.yellow) .onTapGesture { rating = star } } } }}
// Usagestruct ReviewForm: View { @State private var rating = 3
var body: some View { VStack { Text("Rate this product") RatingView(rating: $rating) Text("Your rating: \(rating)/5") } }}Form Fields
Phần tiêu đề “Form Fields”struct FormField: View { let label: String @Binding var text: String var placeholder: String = ""
var body: some View { VStack(alignment: .leading, spacing: 4) { Text(label) .font(.caption) .foregroundColor(.gray)
TextField(placeholder, text: $text) .textFieldStyle(.roundedBorder) } }}
// Usagestruct SignUpForm: View { @State private var name = "" @State private var email = "" @State private var password = ""
var body: some View { VStack(spacing: 16) { FormField(label: "Name", text: $name, placeholder: "Enter name") FormField(label: "Email", text: $email, placeholder: "Enter email") FormField(label: "Password", text: $password) } .padding() }}4. Constant Binding
Phần tiêu đề “4. Constant Binding”Dùng cho preview hoặc testing.
// Không thể thay đổiRatingView(rating: .constant(4))
// Trong Preview#Preview { CustomToggle(isOn: .constant(true))}5. Computed Binding
Phần tiêu đề “5. Computed Binding”struct ContentView: View { @State private var celsius: Double = 25
var fahrenheit: Binding<Double> { Binding( get: { celsius * 9/5 + 32 }, set: { celsius = ($0 - 32) * 5/9 } ) }
var body: some View { VStack { Slider(value: $celsius, in: -40...100) Text("Celsius: \(celsius, specifier: "%.1f")°")
Slider(value: fahrenheit, in: -40...212) Text("Fahrenheit: \(fahrenheit.wrappedValue, specifier: "%.1f")°") } .padding() }}6. Sheet với Binding
Phần tiêu đề “6. Sheet với Binding”struct ContentView: View { @State private var showSheet = false @State private var selectedColor = Color.blue
var body: some View { VStack { Circle() .fill(selectedColor) .frame(width: 100, height: 100)
Button("Choose Color") { showSheet = true } } .sheet(isPresented: $showSheet) { ColorPickerSheet(selectedColor: $selectedColor) } }}
struct ColorPickerSheet: View { @Environment(\.dismiss) var dismiss @Binding var selectedColor: Color
let colors: [Color] = [.red, .blue, .green, .orange, .purple]
var body: some View { VStack { Text("Choose a color") .font(.headline)
HStack { ForEach(colors, id: \.self) { color in Circle() .fill(color) .frame(width: 50, height: 50) .overlay( Circle() .stroke(selectedColor == color ? .black : .clear, lineWidth: 3) ) .onTapGesture { selectedColor = color dismiss() } } } } .padding() }}7. Array Item Binding
Phần tiêu đề “7. Array Item Binding”struct TodoApp: View { @State private var todos = [ Todo(title: "Buy groceries", isComplete: false), Todo(title: "Call mom", isComplete: true) ]
var body: some View { List { ForEach($todos) { $todo in HStack { Toggle("", isOn: $todo.isComplete) .labelsHidden()
Text(todo.title) .strikethrough(todo.isComplete) } } } }}
struct Todo: Identifiable { let id = UUID() var title: String var isComplete: Bool}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Aspect | Detail |
|---|---|
| Mục đích | Two-way binding giữa Views |
| Tạo từ | $stateVariable |
| Nhận | @Binding var property |
| Constant | .constant(value) |
| Custom | Binding(get:set:) |