Widget — un element compact de interfață utilizator pe ecranul principal iOS sau Android, care afișează informații actualizate fără a deschide aplicația. Widgeturile au apărut în iOS 14 (2020) cu framework-ul WidgetKit în SwiftUI și există în Android de la versiunea 1.5 prin AppWidgetProvider în Kotlin sau Java. Acestea permit utilizatorului să vadă vremea, cursul valutar, calendarul, notițele sau statusul sarcinilor direct pe home screen, economisind timp și simplificând interacțiunea. Conform datelor Apple, utilizatorii interacționează cu widgeturile în medie de 4–6 ori pe zi, iar instalarea unui widget pe home screen crește implicarea în aplicație cu 20–30%. Pentru Android aceste cifre sunt comparabile. Să analizăm cum funcționează widgeturile pe ambele platforme, cu exemple de cod.
Principalele puncte
Widget — este un element compact de interfață utilizator plasat pe ecranul principal al dispozitivului mobil pentru afișarea informațiilor actualizate din aplicație. Spre deosebire de o aplicație completă, widgetul nu necesită lansare — utilizatorul vede datele imediat după deblocarea ecranului. Conceptul provine din sistemele desktop (macOS Dashboard, Windows Sidebar), iar în mediul mobil Android a introdus suportul pentru widgeturi de la prima lansare (Android 1.5 Cupcake, 2009), în timp ce Apple le-a adăugat abia în iOS 14.
Implementarea tehnică diferă pe platforme. Widgetul iOS — un target separat în Xcode, compilat ca Widget Extension, care rulează în propriul proces. Widgetul Android — un BroadcastReceiver care extinde AppWidgetProvider, redând layout-ul prin RemoteViews. Ambele platforme impun restricții stricte privind performanța și memoria: sistemul poate elimina widgetul la depășirea limitelor. iOS limitează widgetul la 30–50 MB și timpul de formare a timeline-ului la 10 secunde. Android — intervalul de actualizare nu mai des de 30 de minute prin updatePeriodMillis și terminarea forțată la blocarea onUpdate.
Smart Stack în iOS și stivele în Android permit utilizatorului să grupeze mai multe widgeturi într-un singur slot pe home screen. Dispozitivul comută automat widgetul afișat în funcție de ora zilei, locație sau activitatea utilizatorului. De exemplu, dimineața se arată calendarul, ziua — vremea, seara — notițele. Pentru dezvoltator, aceasta înseamnă că widgetul trebuie să funcționeze corect în cadrul unei stive și să nu se bazeze pe afișarea constantă.
WidgetKit — framework-ul Apple pentru crearea widgeturilor pe iOS 14+, iPadOS 14+ și macOS 11+. Widgeturile se scriu în Swift folosind SwiftUI și mecanismul TimelineProvider pentru actualizarea conținutului. Arhitectura WidgetKit include trei componente: TimelineProvider — sursa de date care formează o axă temporală cu înregistrări; Widget Entry View — SwiftUI View care afișează conținutul pe baza înregistrării; Widget Configuration — descrierea tipului, dimensiunilor și familiilor widgetului.
WidgetKit gestionează singur actualizarea — dezvoltatorul nu poate forța actualizarea widgetului mai des decât permite sistemul. Apple folosește un buget de actualizări distribuit între toate widgeturile de pe dispozitiv. Intervalul minim — 15–30 de minute. Pentru date critice (de exemplu, statusul livrării) se folosește push-to-refresh — trimiterea unei notificări push cu o dată relevantă în viitor, după care WidgetKit solicită un nou timeline. Începând cu iOS 17 widgeturile suportă interactivitatea prin App Intents — utilizatorul poate apăsa butoane în interiorul widgetului fără a deschide aplicația.
| Dimensiune | iOS (pt) | Conținut |
|---|---|---|
| Small | 170 × 170 | 1–2 indicatori: temperatură, curs valutar |
| Medium | 360 × 170 | 2–4 indicatori: prognoză pe 5 zile, listă |
| Large | 360 × 380 | 5–10 indicatori: calendar, flux de știri |
AppWidgetProvider — clasa de bază pentru crearea widgeturilor în Android, inclusă în Android SDK de la API level 3. Widgetul Android — este un BroadcastReceiver care primește evenimente de actualizare, activare și dezactivare de la sistem. Spre deosebire de iOS, unde widgetul este desenat de SwiftUI pe propriul motor, Android folosește RemoteViews — un set limitat de componente View redate în procesul sistemului (launcher). Nu se pot folosi View-uri personalizate, animații complexe sau biblioteci UI.
Schema de funcționare a widgetului Android include patru etape. Configurare — la adăugarea widgetului pe ecran, sistemul poate lansa o Activity de configurare unde utilizatorul alege setările. Actualizare — sistemul apelează onUpdate() la un interval specificat (minimum 30 de minute) sau la semnal din aplicație prin WorkManager. Redare — furnizorul creează RemoteViews cu date actualizate și le transmite prin AppWidgetManager. Procesarea clicurilor — widgetul suportă PendingIntent pentru butoane: la clic se deschide o Activity sau se execută o acțiune. Începând cu Android 12 widgeturile au primit suport pentru colțuri rotunjite, culori adaptive Material You și redimensionare dinamică.
Să creăm un widget meteo în Swift folosind WidgetKit și SwiftUI. Proiectul trebuie să conțină un Widget Extension target, adăugat în Xcode prin File → New → Target → Widget Extension.
import WidgetKit
import SwiftUI
// 1. Model de date pentru widget
struct WeatherEntry: TimelineEntry {
let date: Date
let temperature: Int
let condition: String
}
// 2. TimelineProvider — furnizor de date
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> WeatherEntry {
WeatherEntry(date: Date(), temperature: 22, condition: "Însorit")
}
func getSnapshot(in context: Context, completion: @escaping (WeatherEntry) -> Void) {
let entry = WeatherEntry(date: Date(), temperature: 22, condition: "Însorit")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WeatherEntry>) -> Void) {
let now = Date()
let entry = WeatherEntry(date: now, temperature: 20, condition: "Înnorat")
let nextUpdate = Calendar.current.date(byAdding: .hour, value: 3, to: now)!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
// 3. SwiftUI View pentru afișare
struct WeatherWidgetEntryView: View {
var entry: WeatherEntry
var body: some View {
VStack(alignment: .leading) {
Text("Vreme").font(.caption).foregroundColor(.secondary)
HStack {
Text("\(entry.temperature)°").font(.largeTitle).fontWeight(.bold)
Spacer()
Text(entry.condition).font(.body)
}
}.padding()
}
}
// 4. Configurarea widgetului
@main
struct WeatherWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "WeatherWidget", provider: Provider()) { entry in
WeatherWidgetEntryView(entry: entry)
}
.configurationDisplayName("Vreme")
.description("Arată temperatura curentă")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
Puncte cheie: TimelineProvider determină când și ce date să afișeze; getTimeline creează o axă temporală cu politica de actualizare .after(nextUpdate); StaticConfiguration leagă furnizorul de View. Pentru date dinamice se folosește IntentConfiguration cu parametri utilizator.
Implementăm un widget meteo similar în Kotlin cu AppWidgetProvider și RemoteViews.
// WeatherWidgetProvider.kt
class WeatherWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onAppWidgetOptionsChanged(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
newOptions: Bundle
) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
companion object {
fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val temperature = 20
val condition = "Înnorat"
val views = RemoteViews(
context.packageName, R.layout.widget_weather
).apply {
setTextViewText(R.id.tv_temperature, "$temperature°")
setTextViewText(R.id.tv_condition, condition)
setOnClickPendingIntent(
R.id.widget_root, PendingIntent.getActivity(
context, 0,
Intent(context, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
// AndroidManifest — înregistrarea furnizorului
<receiver android:name=".WeatherWidgetProvider" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_weather_info" />
</receiver>
Fișierul widget_weather_info.xml stabilește dimensiunile minime, intervalul și layout-ul: minWidth 160dp, minHeight 80dp, updatePeriodMillis 3600000 (1 oră). RemoteViews folosește doar componente suportate: LinearLayout, TextView, ImageView. View-uri personalizate și ConstraintLayout sunt disponibile de la Android 5.0. GlanceLayout — abordarea experimentală Compose pentru RemoteViews — a apărut în Android 15.
Întrebări frecvente
iOS WidgetKit oferă trei dimensiuni fixe (small, medium, large) și actualizare prin TimelineProvider cu buget de sistem. Android AppWidgetProvider folosește dimensiuni flexibile în celule, RemoteViews pentru redare și actualizare prin updatePeriodMillis sau WorkManager.
Pe iOS actualizarea este controlată de sistem — interval minim 15–30 de minute, pentru date critice se folosește push-to-refresh. Pe Android intervalul se stabilește în updatePeriodMillis (minimum 30 de minute) sau prin WorkManager pentru sarcini de fundal.
iOS suportă small (170x170pt), medium (360x170pt) și large (360x380pt). Android folosește o grilă flexibilă de celule: de la 2x1 la 5x5, dimensiunea depinde de launcher și versiunea OS.
Pe iOS nu există animații în interiorul widgetului — sunt elemente statice. Android RemoteViews suportă animații de bază prin setFloat() și ViewPropertyAnimator, dar animațiile complexe nu sunt disponibile.
La implementare corectă — nu. Sistemul limitează strict resursele widgetului: pe iOS buget de actualizări și memorie (30–50 MB), pe Android — interval minim de actualizare. Widgeturile problematice sunt terminate forțat de sistem.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și