这里每天分享一个 iOS 的新知识,快来关注我吧
前言
前两天讲了小组件的基础内容,今天准备带大家写一个非常简单的小组件项目。
先说下需求,实现一个可以展示上午、下午、夜里三种状态的小组件,分别用三个不同的图标来显示。
按照上述需求,我们简单地把这个小组件的时间线描述出来,有 3 个阶段:
-
早上 8 点到中午 12 点为上午
-
中午 12 点到下午 6 点为下午
-
下午 6 点到早上 8 点为夜里
TimelineEntry
昨天的文章提到,TimelineEntry
是用来提供小组件显示内容和时间的,那么我们需要先写一个展示时间状态的枚举,用来表示上午、下午和晚上,然后在 SimpleEntry
中声明这个属性:
csharp
struct SimpleEntry: TimelineEntry {
enum Time {
case morning, afternoon, night
}
let date: Date
// 表示上午、下午、晚上
let time: Time
}
Provider
然后是 Provider
的实现,placeholder
方法中直接返回一个固定的 Entry
:
less
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), time: .morning)
}
然后是 getSnapshot
方法,这里依然返回一个固定的 morning
:
less
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), time: .morning)
completion(entry)
}
然后在运行程序,在组件库中就可以看到这个预览了:
最后是最重要的 getTimeline
方法,我们需要在这里把时间线给到系统,我的思路是,先拿到当前时间,判断是上午、下午还是晚上,如果是上午,则添加上午、下午、和晚上的时间条目。如果当前是下午,则添加下午和晚上的时间条目,如果是晚上,则只添加晚上的时间线条目。
首先写个方法来获取指定小时的时间,这个方法传入小时,返回当天这个小时的时间:
sql
func getDate(in hour: Int) -> Date {
let calendar = Calendar.current
var components = calendar.dateComponents([.year, .month, .day], from: Date())
components.hour = hour
components.minute = 0
components.second = 0
return calendar.date(from: components)!
}
然后写具体的时间线条目的代码:
less
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
let hour = Calendar.current.component(.hour, from: Date())
switch hour {
case 8..<12:
entries.append(SimpleEntry(date: Date(), time: .morning))
entries.append(SimpleEntry(date: getDate(in: 12), time: .afternoon))
entries.append(SimpleEntry(date: getDate(in: 18), time: .night))
case 12..<18:
entries.append(SimpleEntry(date: Date(), time: .afternoon))
entries.append(SimpleEntry(date: getDate(in: 18), time: .night))
default:
entries.append(SimpleEntry(date: Date(), time: .night))
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
UI 渲染
为了能够正常显示文案和图标,我给 Time 枚举做了扩展,为不同的 case 返回不同的图标和标题:
swift
extension SimpleEntry.Time {
var text: String {
switch self {
case .morning:
return "上午"
case .afternoon:
return "下午"
case .night:
return "晚上"
}
}
var icon: String {
switch self {
case .morning:
return "sunrise"
case .afternoon:
return "sun.max.fill"
case .night:
return "sunset"
}
}
}
最后是 SwiftUI 渲染代码,我用一个 VStack
包裹外层,里边先是一个图标,然后是个 HStack
来展示文本内容:
scss
struct MyWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack(spacing: 10) {
Image(systemName: entry.time.icon)
.imageScale(.large)
.fontWeight(.medium)
.foregroundColor(.red)
HStack {
Text("现在是:")
Text(entry.time.text)
}
.font(.subheadline)
}
}
}
其他部分的代码不需要改动,保持创建工程时的状态即可。
看下效果
这样,我们的小组件就完成了:
明天继续讲小组件!
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!