Vidjetlar va kengaytmalar
Vidjetlar va ilova kengaytmalari (App Extensions)
Kichik ma’lumotlarni App Groups yordamida ulashing va bir qarashda ko‘rinadigan qisqa ma’lumotlarni ko‘rsatish uchun WidgetKit yordamida vidjetlar yarating.
Vidjet timeline’i
Vaqt yozuvlaridan iborat timeline’ni ko‘rsatadigan vidjet yarating.
Sintaksis:
- timeline provider’ni aniqlash uchun
TimelineProviderprotokoli
Misol
import WidgetKit
import SwiftUI
struct TimeEntry: TimelineEntry { let date: Date }
struct TimeProvider: TimelineProvider {
func placeholder(in context: Context) -> TimeEntry { .init(date: Date()) }
func getSnapshot(in context: Context, completion: @escaping (TimeEntry) -> Void) { completion(.init(date: Date())) }
func getTimeline(in context: Context, completion: @escaping (Timeline<TimeEntry>) -> Void) {
let entries = stride(from: 0, through: 60*30, by: 60).map { offset in
TimeEntry(date: Date().addingTimeInterval(Double(offset)))
}
completion(Timeline(entries: entries, policy: .atEnd))
}
}
struct TimeWidgetView: View {
var entry: TimeEntry
var body: some View { Text(entry.date, style: .time).font(.headline) }
}
@main
struct TimeWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "TimeWidget", provider: TimeProvider()) { e in TimeWidgetView(entry: e) }
}
}
import SwiftUI
struct ContentView: View { var body: some View { Text("Widget timeline demo") } }
import SwiftUI
@main
struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Yuqoridagi misolda placeholder, snapshot va timeline provider’ga ega oddiy vidjet timeline’i ko‘rsatilgan.
Share extension karkasi
Foydalanuvchilarga kontentni ilovangiz bilan ulashish imkonini beradigan share extension yarating.
Sintaksis:
- share extension karkasini aniqlash uchun
ShareExtensionSkeletonstruct’i
Misol
import SwiftUI
struct ShareExtensionSkeleton: View {
@State private var sharedText = ""
var body: some View {
VStack(spacing: 12) {
Text("Incoming content")
TextEditor(text: $sharedText).frame(minHeight: 120).border(.secondary)
HStack { Spacer(); Button("Post") { /* handle share */ } }
}
.padding()
}
}
import SwiftUI
struct ContentView: View { var body: some View { ShareExtensionSkeleton() } }
import SwiftUI
struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Yuqoridagi misolda matn muharriri va yuborish (post) tugmasiga ega oddiy share extension karkasi ko‘rsatilgan.
App Groups (vidjet bilan ma’lumot ulashish)
Ilova uchun ham, vidjet kengaytmasi uchun ham App Groups ni yoqing va kichik ma’lumotlar almashish uchun umumiy suite’dan foydalaning.
Sintaksis: UserDefaults(suiteName: "group.id"), set(_:forKey:) bilan yozing, integer(forKey:) bilan o‘qing.
Nazorat ro‘yxati
- App target’iga va Widget target’iga App Groups imkoniyatini (capability) qo‘shing
- Guruh identifikatorini yarating, masalan,
group.com.example.notes
import Foundation
func updateSharedNotesCount(_ count: Int) {
let defaults = UserDefaults(suiteName: "group.com.example.notes")
defaults?.set(count, forKey: "notesCount")
}
import WidgetKit
import SwiftUI
struct CountEntry: TimelineEntry { let date: Date; let count: Int }
struct NotesProvider: TimelineProvider {
func placeholder(in context: Context) -> CountEntry { .init(date: Date(), count: 0) }
func getSnapshot(in context: Context, completion: @escaping (CountEntry) -> Void) {
let defaults = UserDefaults(suiteName: "group.com.example.notes")
let count = defaults?.integer(forKey: "notesCount") ?? 0
completion(.init(date: Date(), count: count))
}
func getTimeline(in context: Context, completion: @escaping (Timeline<CountEntry>) -> Void) {
let defaults = UserDefaults(suiteName: "group.com.example.notes")
let count = defaults?.integer(forKey: "notesCount") ?? 0
let entries = [CountEntry(date: Date(), count: count)]
completion(Timeline(entries: entries, policy: .after(Date().addingTimeInterval(1800))))
}
}
Ushbu misol qaydlar sonini App Groups orqali ulashadi: ilova qiymatni yozadi, vidjet esa uni ko‘rsatish uchun o‘qiydi.
Vidjetlar
Xcode’da Widget Extension target’ini yarating, so‘ng WidgetKit va SwiftUI yordamida timeline/view’larni loyihalang.
Sintaksis: TimelineProvider ni realizatsiya qiling, Widget ni e’lon qiling va StaticConfiguration(kind:provider:content:) ni qaytaring.
Misol
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry { .init(date: Date()) }
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { completion(.init(date: Date())) }
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
completion(Timeline(entries: [.init(date: Date())], policy: .atEnd))
}
}
struct SimpleEntry: TimelineEntry { let date: Date }
struct MyWidgetEntryView: View {
var entry: SimpleEntry
var body: some View { Text(entry.date, style: .time) }
}
@main
struct MyWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
MyWidgetEntryView(entry: entry)
}
}
}
}
Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.
Vidjetlardan deep link’lar
URL taqdim etish orqali vidjet bosilganda ilovangizni muayyan ekranda oching.
Sintaksis: Link va onOpenURL ni realizatsiya qiling.
Misol
import SwiftUI
struct NotesCountView: View {
var body: some View {
Link(destination: URL(string: "myapp://notes")!) {
Text("Notes: \(entry.count)")
}
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
// Route based on url.host / path (e.g., "notes")
}
}
}
}
Yuqoridagi misolda muayyan ekranga havolasi bor oddiy vidjet va URL’ni qayta ishlaydigan ilova ko‘rsatilgan.
Yangilash va timeline siyosati
Yangilash strategiyasini tanlang va ma’lumotlar o‘zgarganda qayta yuklashni ishga tushiring.
Sintaksis: TimelineProvider va WidgetCenter ni realizatsiya qiling.
Misol
import WidgetKit
// Update at a future date
completion(Timeline(entries: entries, policy: .after(Date().addingTimeInterval(1800))))
// Or end when entries are exhausted
// completion(Timeline(entries: entries, policy: .atEnd))
import WidgetKit
// Refresh a specific widget kind after writing new data to App Group
WidgetCenter.shared.reloadTimelines(ofKind: "NotesCount")
// Or refresh all widget kinds
// WidgetCenter.shared.reloadAllTimelines()
Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.
Qo‘llab-quvvatlanadigan oilalar (families)
Vidjetingiz qaysi o‘lchamlarni qo‘llab-quvvatlashini e’lon qiling.
Sintaksis: WidgetConfiguration va supportedFamilies ni realizatsiya qiling.
Misol
import WidgetKit
@main
struct NotesCountWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "NotesCount", provider: NotesProvider()) { entry in
NotesCountView(entry: entry)
}
.supportedFamilies([.systemSmall, .systemMedium])
}
}
Yuqoridagi misolda timeline provider va statik konfiguratsiyaga ega oddiy vidjet ko‘rsatilgan.
Vidjetlarni testlash
Sintaksis: WidgetPreviewProvider va WidgetCenter ni realizatsiya qiling.
- Widget preview provider’laridan foydalaning va vidjetni Home/Lock ekraniga qo‘shib, qurilmada sinab ko‘ring.
- Yangilanishni tekshirish uchun App Group qiymatlarini o‘zgartiring va
WidgetCenter.shared.reloadTimelinesni chaqiring. - Turli oilalarni (small/medium/large) va qorong‘i/yorug‘ rejimni tekshiring.
W3Schools Pathfinder
Yutuqlaringizni kuzating – bu bepul!
