Section 5/141 menit
5. Sintaks Dasar: Widget Pertama
5. Sintaks Dasar: Widget Pertama
Tiga Komponen Utama
Setiap widget membutuhkan tiga komponen: Entry (data), Provider (sumber data + timeline), View (tampilan).
swift
import WidgetKit
import SwiftUI
// 1. Entry — data model untuk satu snapshot widget
struct HabitEntry: TimelineEntry {
let date: Date // WAJIB — kapan entry ini valid
let habitName: String
let isCompleted: Bool
let streak: Int
}
// 2. Provider — menghasilkan entry untuk snapshot dan timeline
struct HabitProvider: TimelineProvider {
// Dipanggil untuk placeholder saat widget pertama kali muncul
func placeholder(in context: Context) -> HabitEntry {
HabitEntry(date: Date(), habitName: "Olahraga", isCompleted: false, streak: 7)
}
// Dipanggil untuk preview di widget gallery
func getSnapshot(in context: Context, completion: @escaping (HabitEntry) -> Void) {
let entry = HabitEntry(date: Date(), habitName: "Olahraga", isCompleted: true, streak: 14)
completion(entry)
}
// Dipanggil untuk timeline aktual
func getTimeline(in context: Context, completion: @escaping (Timeline<HabitEntry>) -> Void) {
let sharedDefaults = UserDefaults(suiteName: "group.com.perusahaan.namaapp")
let habitName = sharedDefaults?.string(forKey: "currentHabit") ?? "Olahraga"
let isCompleted = sharedDefaults?.bool(forKey: "habitCompletedToday") ?? false
let streak = sharedDefaults?.integer(forKey: "streak") ?? 0
let entry = HabitEntry(
date: Date(),
habitName: habitName,
isCompleted: isCompleted,
streak: streak
)
// Refresh di tengah malam untuk reset status harian
let midnight = Calendar.current.startOfDay(for: Date().addingTimeInterval(86400))
let timeline = Timeline(entries: [entry], policy: .after(midnight))
completion(timeline)
}
}
// 3. View — SwiftUI view yang dirender oleh sistem
struct HabitWidgetView: View {
let entry: HabitEntry
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Image(systemName: entry.isCompleted ? "checkmark.circle.fill" : "circle")
.foregroundStyle(entry.isCompleted ? .green : .secondary)
Text(entry.habitName)
.font(.headline)
}
Text("🔥 \(entry.streak) hari streak")
.font(.caption)
.foregroundStyle(.orange)
}
.padding()
.containerBackground(.fill.tertiary, for: .widget)
}
}
// 4. Widget definition
struct HabitWidget: Widget {
let kind: String = "HabitWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: HabitProvider()) { entry in
HabitWidgetView(entry: entry)
}
.configurationDisplayName("Habit Tracker")
.description("Pantau habit harianmu langsung dari Home Screen.")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
WidgetBundle untuk Multiple Widgets
swift
// MyAppWidgetBundle.swift — entry point untuk semua widget dalam satu extension
@main
struct MyAppWidgetBundle: WidgetBundle {
var body: some Widget {
HabitWidget()
WeatherWidget()
QuoteOfTheDayWidget()
}
}