Widget คือองค์ประกอบอินเทอร์เฟซผู้ใช้ขนาดกะทัดรัดบนหน้าจอหลักของ iOS หรือ Android ที่แสดงข้อมูลที่เกี่ยวข้องโดยไม่ต้องเปิดแอป วิดเจ็ตปรากฏใน iOS 14 (2020) พร้อมเฟรมเวิร์ก WidgetKit บน SwiftUI และมีอยู่ใน Android ตั้งแต่เวอร์ชัน 1.5 ผ่าน AppWidgetProvider บน Kotlin หรือ Java วิดเจ็ตช่วยให้ผู้ใช้เห็นสภาพอากาศ อัตราแลกเปลี่ยน ปฏิทิน โน้ต หรือสถานะงานโดยตรงบนหน้าจอหลัก ประหยัดเวลาและทำให้การโต้ตอบง่ายขึ้น ตามข้อมูลของ Apple ผู้ใช้โต้ตอบกับวิดเจ็ตโดยเฉลี่ย 4–6 ครั้งต่อวัน และการวางวิดเจ็ตบนหน้าจอหลักช่วยเพิ่มการมีส่วนร่วมกับแอปขึ้น 20–30% สำหรับ Android ตัวเลขเหล่านี้ใกล้เคียงกัน มาดูกันว่าวิดเจ็ตทำงานบนทั้งสองแพลตฟอร์มอย่างไรพร้อมตัวอย่างโค้ด
ประเด็นสำคัญ
Widget คือองค์ประกอบอินเทอร์เฟซผู้ใช้ขนาดกะทัดรัดที่วางบนหน้าจอหลักของอุปกรณ์มือถือเพื่อแสดงข้อมูลที่เกี่ยวข้องจากแอป แตกต่างจากแอปพลิเคชันเต็มรูปแบบ วิดเจ็ตไม่ต้องเปิดใช้งาน — ผู้ใช้เห็นข้อมูลทันทีหลังจากปลดล็อกหน้าจอ แนวคิดนี้มาจากระบบปฏิบัติการเดสก์ท็อป (macOS Dashboard, Windows Sidebar) และในสภาพแวดล้อมมือถือ Android ได้แนะนำการรองรับวิดเจ็ตตั้งแต่รุ่นแรก (Android 1.5 Cupcake, 2009) ในขณะที่ Apple เพิ่มเข้ามาใน iOS 14 เท่านั้น
การใช้งานทางเทคนิค แตกต่างกันไปตามแพลตฟอร์ม วิดเจ็ต iOS คือ target แยกต่างหากใน Xcode ซึ่งคอมไพล์เป็น Widget Extension ทำงานในกระบวนการของตัวเอง วิดเจ็ต Android คือ BroadcastReceiver ที่ขยาย AppWidgetProvider แสดงเลย์เอาต์ผ่าน RemoteViews ทั้งสองแพลตฟอร์มกำหนดข้อจำกัดด้านประสิทธิภาพและหน่วยความจำที่เข้มงวด: ระบบอาจลบวิดเจ็ตหากเกินขีดจำกัด iOS จำกัดวิดเจ็ตไว้ที่ 30–50 MB และเวลาในการสร้าง timeline ไว้ที่ 10 วินาที Android — ช่วงเวลาอัปเดตไม่เกิน 30 นาทีผ่าน updatePeriodMillis และการบังคับสิ้นสุดหาก onUpdate ค้าง
Smart Stack บน iOS และสแตกบน Android อนุญาตให้ผู้ใช้รวมวิดเจ็ตหลายตัวในช่องหน้าจอหลักเดียว อุปกรณ์จะสลับวิดเจ็ตที่แสดงโดยอัตโนมัติตามช่วงเวลาของวัน ตำแหน่ง หรือกิจกรรมของผู้ใช้ ตัวอย่างเช่น ในตอนเช้าแสดงปฏิทิน กลางวัน — สภาพอากาศ เย็น — โน้ต สำหรับนักพัฒนา หมายความว่าวิดเจ็ตต้องทำงานอย่างถูกต้องในฐานะส่วนหนึ่งของสแตกและไม่พึ่งพาการแสดงผลอย่างต่อเนื่อง
WidgetKit คือเฟรมเวิร์กของ Apple สำหรับสร้างวิดเจ็ตบน iOS 14+, iPadOS 14+ และ macOS 11+ วิดเจ็ตเขียนด้วย Swift โดยใช้ SwiftUI และกลไก TimelineProvider สำหรับการอัปเดตเนื้อหา สถาปัตยกรรม WidgetKit ประกอบด้วยสามองค์ประกอบ: TimelineProvider — แหล่งข้อมูลที่สร้างไทม์ไลน์พร้อมรายการ; Widget Entry View — SwiftUI View ที่แสดงเนื้อหาตามรายการ; Widget Configuration — คำอธิบายประเภท ขนาด และตระกูลของวิดเจ็ต
WidgetKit จัดการการอัปเดตโดยอัตโนมัติ — นักพัฒนาไม่สามารถบังคับให้วิดเจ็ตอัปเดตบ่อยเกินกว่าระบบอนุญาต Apple ใช้งบประมาณการอัปเดตที่กระจายระหว่างวิดเจ็ตทั้งหมดบนอุปกรณ์ ช่วงเวลาขั้นต่ำคือ 15–30 นาที สำหรับข้อมูลสำคัญ (เช่น สถานะการจัดส่ง) จะใช้ push-to-refresh — การส่งการแจ้งเตือนแบบพุชพร้อมวันที่ในอนาคตที่เกี่ยวข้อง หลังจากนั้น WidgetKit จะขอไทม์ไลน์ใหม่ ตั้งแต่ iOS 17 วิดเจ็ตรองรับการโต้ตอบผ่าน App Intents — ผู้ใช้สามารถกดปุ่มภายในวิดเจ็ตโดยไม่ต้องเปิดแอป
| ขนาด | iOS (pt) | เนื้อหา |
|---|---|---|
| Small | 170 × 170 | 1–2 ตัวชี้วัด: อุณหภูมิ, อัตราแลกเปลี่ยน |
| Medium | 360 × 170 | 2–4 ตัวชี้วัด: พยากรณ์ 5 วัน, รายการ |
| Large | 360 × 380 | 5–10 ตัวชี้วัด: ปฏิทิน, ฟีดข่าว |
AppWidgetProvider คือคลาสพื้นฐานสำหรับสร้างวิดเจ็ตบน Android ซึ่งเป็นส่วนหนึ่งของ Android SDK ตั้งแต่ API level 3 วิดเจ็ต Android คือ BroadcastReceiver ที่รับเหตุการณ์อัปเดต เปิดใช้งาน และปิดใช้งานจากระบบ แตกต่างจาก iOS ที่วิดเจ็ตแสดงผลด้วย SwiftUI บนเอนจินของตัวเอง Android ใช้ RemoteViews — ชุดส่วนประกอบ View ที่จำกัดซึ่งแสดงผลในกระบวนการระบบ (launcher) ไม่สามารถใช้ View ที่กำหนดเอง อนิเมชันที่ซับซ้อน หรือไลบรารี UI ได้
ขั้นตอนการทำงานของวิดเจ็ต Android ประกอบด้วยสี่ขั้นตอน การกำหนดค่า — เมื่อเพิ่มวิดเจ็ตลงในหน้าจอ ระบบอาจเปิด Activity การกำหนดค่าที่ผู้ใช้เลือกการตั้งค่า การอัปเดต — ระบบเรียก onUpdate() ตามช่วงเวลาที่กำหนด (ขั้นต่ำ 30 นาที) หรือตามสัญญาณจากแอปผ่าน WorkManager การแสดงผล — ผู้ให้บริการสร้าง RemoteViews ด้วยข้อมูลปัจจุบันและส่งผ่าน AppWidgetManager การจัดการการแตะ — วิดเจ็ตรองรับ PendingIntent สำหรับปุ่ม: การคลิกเปิด Activity หรือดำเนินการ ตั้งแต่ Android 12 วิดเจ็ตได้รับการรองรับมุมโค้ง สีที่ปรับเปลี่ยนได้ของ Material You และการเปลี่ยนแปลงขนาดแบบไดนามิก
มาสร้างวิดเจ็ตสภาพอากาศใน Swift โดยใช้ WidgetKit และ SwiftUI โปรเจกต์ต้องมี Widget Extension target ซึ่งเพิ่มใน Xcode ผ่าน File → New → Target → Widget Extension
import WidgetKit
import SwiftUI
// 1. โมเดลข้อมูลสำหรับวิดเจ็ต
struct WeatherEntry: TimelineEntry {
let date: Date
let temperature: Int
let condition: String
}
// 2. TimelineProvider — ผู้ให้บริการข้อมูล
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> WeatherEntry {
WeatherEntry(date: Date(), temperature: 22, condition: "แดดจัด")
}
func getSnapshot(in context: Context, completion: @escaping (WeatherEntry) -> Void) {
let entry = WeatherEntry(date: Date(), temperature: 22, condition: "แดดจัด")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WeatherEntry>) -> Void) {
let now = Date()
let entry = WeatherEntry(date: now, temperature: 20, condition: "มีเมฆมาก")
let nextUpdate = Calendar.current.date(byAdding: .hour, value: 3, to: now)!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
// 3. SwiftUI View สำหรับการแสดงผล
struct WeatherWidgetEntryView: View {
var entry: WeatherEntry
var body: some View {
VStack(alignment: .leading) {
Text("สภาพอากาศ").font(.caption).foregroundColor(.secondary)
HStack {
Text("\(entry.temperature)°").font(.largeTitle).fontWeight(.bold)
Spacer()
Text(entry.condition).font(.body)
}
}.padding()
}
}
// 4. การกำหนดค่าวิดเจ็ต
@main
struct WeatherWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "WeatherWidget", provider: Provider()) { entry in
WeatherWidgetEntryView(entry: entry)
}
.configurationDisplayName("สภาพอากาศ")
.description("แสดงอุณหภูมิปัจจุบัน")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
ประเด็นสำคัญ: TimelineProvider กำหนดเมื่อใดและข้อมูลใดที่จะแสดง; getTimeline สร้างไทม์ไลน์ด้วยนโยบายการอัปเดต .after(nextUpdate); StaticConfiguration เชื่อมต่อผู้ให้บริการกับ View สำหรับข้อมูลแบบไดนามิก จะใช้ IntentConfiguration พร้อมพารามิเตอร์ที่กำหนดเอง
มาลงใช้วิดเจ็ตสภาพอากาศที่คล้ายกันใน Kotlin ด้วย AppWidgetProvider และ 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 = "มีเมฆมาก"
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 — การลงทะเบียนผู้ให้บริการ
<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>
ไฟล์ widget_weather_info.xml กำหนดขนาดขั้นต่ำ ช่วงเวลา และเลย์เอาต์: minWidth 160dp, minHeight 80dp, updatePeriodMillis 3600000 (1 ชั่วโมง) RemoteViews ใช้เฉพาะส่วนประกอบที่รองรับ: LinearLayout, TextView, ImageView View ที่กำหนดเองและ ConstraintLayout พร้อมใช้งานตั้งแต่ Android 5.0 GlanceLayout — แนวทางทดลองที่ใช้ Compose สำหรับ RemoteViews — ปรากฏใน Android 15
คำถามที่พบบ่อย
iOS WidgetKit มีสามขนาดคงที่ (small, medium, large) และอัปเดตผ่าน TimelineProvider พร้อมงบประมาณของระบบ Android AppWidgetProvider ใช้ขนาดที่ยืดหยุ่นตามเซลล์ RemoteViews สำหรับการแสดงผล และอัปเดตผ่าน updatePeriodMillis หรือ WorkManager
บน iOS ระบบควบคุมการอัปเดต — ช่วงเวลาขั้นต่ำคือ 15–30 นาที สำหรับข้อมูลสำคัญจะใช้ push-to-refresh บน Android ช่วงเวลาถูกกำหนดใน updatePeriodMillis (ขั้นต่ำ 30 นาที) หรือผ่าน WorkManager สำหรับงานเบื้องหลัง
iOS รองรับ small (170x170pt), medium (360x170pt) และ large (360x380pt) Android ใช้กริดเซลล์ที่ยืดหยุ่น: จาก 2x1 ถึง 5x5 ขนาดขึ้นอยู่กับ launcher และเวอร์ชันระบบปฏิบัติการ
บน iOS อนิเมชันภายในวิดเจ็ตไม่สามารถใช้ได้ — เป็นองค์ประกอบคงที่ Android RemoteViews รองรับอนิเมชันพื้นฐานผ่าน setFloat() และ ViewPropertyAnimator แต่อนิเมชันที่ซับซ้อนไม่สามารถใช้ได้
ด้วยการใช้งานที่ถูกต้อง — ไม่ ระบบจำกัดทรัพยากรวิดเจ็ตอย่างเข้มงวด: บน iOS — งบประมาณการอัปเดตและหน่วยความจำ (30–50 MB) บน Android — ช่วงเวลาอัปเดตขั้นต่ำ วิดเจ็ตที่มีปัญหาจะถูกบังคับสิ้นสุดโดยระบบ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม