-2

Xây dựng Widget với WidgetKit và SwiftUI

WidgetKit là một framework được giới thiệu trong WWDC 20. Sử dụng WidgetKit, các developer có thể tạo các widget có thể hiển thị trên màn hình chính.
Các widget được viết bằng SwiftUI và widget chỉ có sẵn cho iOS 14 trở lên. Ở bài viết này, mình sẽ hướng dẫn các bạn có thể hiểu được các phần cấu tạo và viết một widget cơ bản.
Let's go...!

Thêm Target Widget vào dự án

Chúng ta có thể thêm Widget Extension từ thanh menu File -> New -> Target. Tìm kiếm Widget Extension -> Next. Bây giờ bạn có thể đặt tên cho widget của mình và quá trình thiết lập đã sẵn sàng!.

Mình sẽ sử dụng luôn example của Apple sinh ra để hướng dẫn các bạn:

Xây dựng Widget

Widget của bạn là một cấu trúc ghi đè lớp Widget. Nó chứa cấu hình cơ bản cho widget của bạn:

@main
struct DateWidget: Widget {
    let kind: String = "DateWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            DateWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

Trong đoạn mã trên, một widget mới có tên là DateWidget được tạo. Phần thân chứa phần khởi tạo widget. Một StaticConfiguration bao gồm:

  • Kind: identifier duy nhất cho widget. Bạn có thể điền vào bất kỳ identifier nào bạn muốn. Bạn cần identifier này nếu bạn muốn refresh widget của mình từ ứng dụng.
  • Provider: Provider cần thiết để xác định tiến trình làm mới widget của bạn.
  • Closure: Đóng nội dung chứa chế độ xem tiện ích cần được hiển thị cho người dùng (cho mọi kích thước), đây chính là nơi bạn vẽ view để hiển thị lên giao diện. Ví dụ mình có sẽ một DateWidgetEntryView như sau:
struct DateWidgetEntryView : View {
    var entry: Provider.Entry
    
    var body: some View {
           Text(entry.date, style: .time)
    }
}

Bạn cũng có thể chỉ định các size bằng các thêm .supportedFamilies([.systemLarge, .systemMedium, .systemSmall])

TimelineEntry

TimelineEntry chỉ định ngày hiển thị Widget, bạn cũng có thể khai báo thêm các thuộc tính đưa vào để hiển thị lên view ở đây.

struct SimpleEntry: TimelineEntry {
    let date: Date
    // other properties
}

Provider

Placeholder

Tiếp theo, mình thực thi placeholder và trả về một đối tượng SimpleEntry với ngày hiện tại. Điều này cho WidgetKit biết những gì sẽ hiển thị trong khi widget đang tải.

func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date())
    }

getTimeLine

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
  • getTimeline(context:completion:): Cung cấp một Đối tượng Timeline có các entry cho thời điểm hiện tại và bất kỳ thời điểm nào trong tương lai để cập nhật widget. Như ở ví dụ trên, mình cung cấp một đối tượng TimeLine có entry là một mảng các SimpleEntry mà mình đã thiết lập ở trước. Mình xây dựng date cho mỗi entry là sau 1 giờ. Sau đó WidgetKit sẽ yêu cầu làm mới bằng cách sử dụng policy(TimelineReloadPolicy) .atEnd.
    Hiện có 3 policy cập nhật có sẵn trong WidgetKit:
  • .atEnd WidgetKit sẽ yêu cầu Timeline mới sau khi ngày cuối cùng trong dòng thời gian trôi qua.
  • .after (_) Chỉ định một ngày tương lai mà WidgetKit sẽ yêu cầu Timeline mới.
  • .never dựa vào ứng dụng để làm mới dòng thời gian theo cách thủ công bằng cách gọi một trong các chức năng tải lại được tích hợp sẵn. Ví dụ WidgetCenter.shared.reloadAllTimelines () hoặc WidgetCenter.shared.reloadTimelines(ofKind:)

getSnapshot (context:complete:)

func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date())
        completion(entry)
    }
  • getSnapshot (context:complete:): Cung cấp một timeline entry thể hiện trạng thái hiện tại của widget.

Kích thước widget

Bạn có thể cài đặt kích thước của tiện ích bằng cách xác định Environment của widgetFamily. Sau đó, bạn có thể kiểm tra kiểu kích thước widget. Kích thước có thể là systemSmall, systemMedium hoặc systemLarge.

struct DateWidgetEntryView : View {
    var entry: Provider.Entry
    
    @Environment(\.widgetFamily) private var family

    var body: some View {
        switch family {
        case .systemSmall:
            Text(entry.date, style: .time)
        case .systemMedium:
            Text(entry.date, style: .time)
        case .systemLarge:
            Text(entry.date, style: .time)
        }
    }
}

Khai báo nhiều Widget trong ứng dụng

Một ứng dụng thì có thể tạo nhiều Widget Extension khác nhau, để tạo nhiều widget, bạn cần tạo một struct conform WidgetBundle. Thêm thuộc tính @main(ở version iOS 14 nó là @UIApplication) vào đầu cấu trúc này để cho WidgetKit biết rằng Widget Extension của bạn hỗ trợ nhiều widget. Ví dụ:

@main
struct DateWidgets: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        DateWidget()
        DateWidget2()
        DateWidget3()
    }
}

Kết quả


Chúc các bạn thành công!!!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí