Published on

WidgetKit — bosh ekran vidjetlari

Authors

WidgetKit — ilovangizning muhim ma'lumotlarini bosh ekranda ko'rsatish uchun framework. Ob-havo, vazifalar ro'yxati, sport natijalari, buyurtma holati — foydalanuvchi ilovani ochmasdan eng kerakli ma'lumotni ko'radi.

Widget SwiftUI View dan iborat, lekin u interaktiv emas (iOS 17 gacha). U Timeline asosida ishlaydi — siz tizimga qachon qanday ma'lumot ko'rsatishni aytasiz, tizim esa o'z vaqtida yangilaydi. Widget ilovadan alohida target sifatida yaratiladi.

Widget yaratish bosqichlari

Xcode da:
1. FileNewTarget
2. "Widget Extension" ni tanlang
3. Nomini yozing (masalan: "MeningVidjetim")
4. "Include Configuration App Intent" ni tanlang
5. Finish

Widget tuzilishi

import WidgetKit
import SwiftUI

// ═══════════════════════════════════════
//  1. ENTRY — vidjet ma'lumoti
// ═══════════════════════════════════════
struct VazifaEntry: TimelineEntry {
    let date: Date  // Majburiy — qachon ko'rsatilishi
    let vazifaSoni: Int
    let birinchiVazifa: String
}

// ═══════════════════════════════════════
//  2. PROVIDER — ma'lumot beruvchi
// ═══════════════════════════════════════
struct VazifaProvider: TimelineProvider {
    // Placeholder — yuklanayotganda
    func placeholder(in context: Context) -> VazifaEntry {
        VazifaEntry(date: .now, vazifaSoni: 3, birinchiVazifa: "Namuna vazifa")
    }

    // Snapshot — galereya da ko'rsatish
    func getSnapshot(in context: Context,
                     completion: @escaping (VazifaEntry) -> Void) {
        let entry = VazifaEntry(date: .now, vazifaSoni: 5,
                                birinchiVazifa: "SwiftUI o'rganish")
        completion(entry)
    }

    // Timeline — haqiqiy ma'lumot
    func getTimeline(in context: Context,
                     completion: @escaping (Timeline<VazifaEntry>) -> Void) {
        // Ma'lumotni olish (UserDefaults, API va h.k.)
        let vazifaSoni = UserDefaults(suiteName: "group.com.app.vazifalar")?
            .integer(forKey: "vazifaSoni") ?? 0
        let birinchi = UserDefaults(suiteName: "group.com.app.vazifalar")?
            .string(forKey: "birinchiVazifa") ?? "Vazifa yo'q"

        let entry = VazifaEntry(
            date: .now,
            vazifaSoni: vazifaSoni,
            birinchiVazifa: birinchi
        )

        // 30 daqiqadan keyin yangilash
        let keyingiYangilash = Calendar.current.date(
            byAdding: .minute, value: 30, to: .now
        )!

        let timeline = Timeline(
            entries: [entry],
            policy: .after(keyingiYangilash)
        )
        completion(timeline)
    }
}

// ═══════════════════════════════════════
//  3. VIEW — vidjet ko'rinishi
// ═══════════════════════════════════════
struct VazifaVidjetView: View {
    var entry: VazifaEntry
    @Environment(\.widgetFamily) var hajm

    var body: some View {
        switch hajm {
        case .systemSmall:
            // Kichik vidjet
            VStack(alignment: .leading) {
                HStack {
                    Image(systemName: "checklist")
                    Text("\(entry.vazifaSoni)")
                        .font(.title.bold())
                }
                Text(entry.birinchiVazifa)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            .padding()
        case .systemMedium:
            // O'rta vidjet
            HStack {
                VStack(alignment: .leading) {
                    Text("Vazifalar")
                        .font(.headline)
                    Text("\(entry.vazifaSoni) ta bajarilmagan")
                        .foregroundStyle(.secondary)
                }
                Spacer()
                Text("\(entry.vazifaSoni)")
                    .font(.system(size: 44, weight: .bold))
                    .foregroundStyle(.blue)
            }
            .padding()
        default:
            Text("Vazifalar: \(entry.vazifaSoni)")
        }
    }
}

// ═══════════════════════════════════════
//  4. WIDGET — barchasini birlashtirish
// ═══════════════════════════════════════
struct VazifaVidjeti: Widget {
    let kind = "VazifaVidjeti"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: VazifaProvider()) { entry in
            VazifaVidjetView(entry: entry)
                .containerBackground(.fill.tertiary, for: .widget)
        }
        .configurationDisplayName("Vazifalar")
        .description("Bajarilmagan vazifalaringizni ko'ring")
        .supportedFamilies([.systemSmall, .systemMedium])
    }
}

Ilovadan vidjetni yangilash

// Asosiy ilova ichida — vazifa o'zgarganda
import WidgetKit

func vazifaYangilandi() {
    // App Group orqali ma'lumot yozish
    let defaults = UserDefaults(suiteName: "group.com.app.vazifalar")
    defaults?.set(vazifalar.count, forKey: "vazifaSoni")
    defaults?.set(vazifalar.first?.nomi ?? "", forKey: "birinchiVazifa")

    // Vidjetni yangilash
    WidgetCenter.shared.reloadAllTimelines()
}

🎯 Topshiriq

"Vazifalar" vidjeti yarating: kichik vidjetda soni, o'rta vidjetda ro'yxat. App Group orqali asosiy ilovadan ma'lumot uzatish. widgetURL() bilan vidjetga bosganda ilova ochilishi.

Buy mea coffee