iOS 14 giới thiệu đến người dùng một tính năng mới cực "hot" là widget, giúp cập nhật thông tin một cách nhanh chóng và giao diện thú vị hơn. Trong bài viết hôm nay, mình giới thiệu cách tạo Widget đơn giản bằng SwiftUI trên iOS14
Ở đây mình sử dụng XCode 12 và tạo Project có tên là "DemoWidget"
Sau khi tạo xong, chúng ta cần thêm Widget Extension cho Project
Mình sẽ đặt tên cho Widget là "MyPetWidget". Sau khi tạo xong Project của chúng ta sẽ có cấu trúc thư mục như sau
Trong Demo này mình sẽ tạo ra một Widget đơn giản ở ngoài màn hình Home, ảnh sẽ được thay đổi theo thời gian. Đầu tiên chúng ta sẽ định nghĩa một model là MyPet gồm 2 thuộc tính là name và photo
Lưu ý khi tạo Model, phải add Target cho cả Widget Extension
Tiếp đó, mình sẽ kéo vào thư mục Assets của Widget một số bức hình sử dụng trong demo
Tạo file Repository.swift. Ở đây mình sẽ khai báo class Repository chịu trách nhiệm sinh Data để sử dụng trong ứng dụng
Mở file MyPhotoWidget.swift và kéo xuống phần khai báo MyPhotoWidget, đây là phần quyết định nội dung của Widget
Có thể thấy MyPhotoWidget conforms Widget Protocol, trong đó khai báo body trả về một WidgetConfiguration. Có 2 loại Configuration là IntentConfiguration và StaticConfiguration IntentConfiguration cho phép chúng ta thực hiện một số cấu hình và mất thêm một chút thời gian để thiết lập. Trong bài viết này, mình sẽ chỉ sử dụng StaticConfiguration
Kéo lên một chút ta sẽ thấy đoạn code SimpleEntry. Có thể hiểu đây là model được sử dụng cho Widget. Chúng ta sẽ sửa lại model này để phù hợp với nội dung App. Thay đoạn mã trên bằng đoạn mã của chúng ta
MyPetEntry có kiểu TimeLineEntry. Trong đó bắt buộc phải khai báo biến date để dựa vào đó cập nhật Widget theo thời gian
Mặc định Apple sẽ tạo sẵn một InentConfiguration
Chúng ta sẽ thay đổi đoạn code này sử dụng StaticConfiguration. Bạn sẽ thấy XCode báo một số lỗi, chúng ta sẽ cần sửa thêm ở vài chỗ nữa
Kéo lên phần Provider. Do chúng ta thay đổi SimpleEntry thành MypetEntry, sử dụng StaticConfiguration thay vì IntentConfiguration, Provider vì thế cũng cần conform các protocol khác Thay thế IntentTimelineProvider thành TimelineProvider và thay đổi nội dung của Provider thành như sau
Đoạn mã trên sẽ quyết định content sẽ được render trên Widget của chúng ta, Provider sẽ là cầu nối giữa code và UI của chúng ta trông qua timeline. TimelineProvider yêu cầu định nghĩa một kiểu cho Entry, ở đây chúng ta cần data ở dạng MyPetEntry, do đó chúng ta sẽ thêm typealias Entry = MovieEntry. Tiếp đó implement function placeholder(in context:) và trả về một MovieEntry Object chứa MyPet() mặc định. Hàm này được sử dụng cho WidgetKit render trong lúc loading
Tiếp đến là hàm getTimeline(context:completion:) . Nhiệm vụ của hàm này là cấp cho Timeline object chứa nhiều Entries. Trong trường hợp này chúng ta sẽ cung cấp cho mỗi entry một MyPet thông qua MyPetEntry đã setup ở trên. Sau đó tạo ra cho mỗi Entry một date tương ứng với thời gian tồn tại. Hết khoảng thời gian này, entry tiếp theo sẽ được hiển thị để thay thế cho entry hiện tại bằng việc set policy cho Widget ở chế độ .atEnd, ở đây mình sẽ để 30 giây.
Trong demo này, chúng ta được sử dụng data tĩnh tại local, vậy nếu chúng ta phải thực hiện query để call API lên server và Widget ở trong trạng thái Preview thì Widget sẽ hiển thị như thế nào ?. Đó là lúc chúng ta dùng tới hàm getSnapshot(context:completion:). Khi đó Widget có thể kiểm tra context.isPreview và cung cấp một dữ liệu mẫu, nhờ đó Widget có thể hiển thị ngay lập tức. Hàm này không cần thiết trong Demo này, nhưng mình vẫn sẽ nhắc tới để có thể nắm được ý nghĩa của nó Bước cuối cùng là tạo UI. Thay thế MyPhotoWidgetEntryView bằng đoạn code sau. Ở đây sử dụng ZStack với một Image hiển thị full Widget background, sau đó dùng 2 VStack, một để tạo ra vùng Gradient, một để hiển thị Text là tên MyPet
Muốn hiển thị Preview trong lúc Code như hình trên thì các bạn cần sửa thêm một chút MyPhotoWidget_Previews, cấp cho nó một MyPhotoWidgetEntryView mặc định để hiển thị
Build Project và chúng ta thu được kết quả như trong hình
Nguồn tham khảo
https://www.swiftcompiled.com/homescreen-widgets/
Full Source Code
https://github.com/buixuanhuy5798/WidgetDemo/tree/master/MyPhotoWidget