前言
前面了解了 Text 相关的过渡动画,这两天了解到小组件也是可以展示动画的。在 iOS 17 之前动画一直是被禁用的,但是仍有人在小组件上实现了动画效果,这里记录一下小组件实现动画的几种方式。
帧动画
利用小组件的时间线机制,每秒调用一次 reloadAllTimelines 方法刷新UI来达到动画效果,如下效果(如需查看源码请看参考链接):
我们也可以借此思路实现一个简版时钟,代码如下
// AnimateWidget.swift
import WidgetKit
import SwiftUI
struct AnimateEntry: TimelineEntry {
let date: Date
}
struct AnimateProvider: TimelineProvider {
func placeholder(in context: Context) -> AnimateEntry {
AnimateEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (AnimateEntry) -> ()) {
let entry = AnimateEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [AnimateEntry] = []
let currentDate = Date()
let entry = AnimateEntry(date: currentDate)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct AnimateWidgetEntryView : View {
var entry: Provider.Entry
private let longDateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
return formatter
}()
private func tick() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
WidgetCenter.shared.reloadAllTimelines()
tick()
}
}
var body: some View {
VStack {
Text("\(entry.date, formatter: longDateFormat)")
.font(.footnote)
.onAppear() {
tick()
}
}
}
}
struct AnimateWidget: Widget {
let kind: String = "AnimateWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
AnimateWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
.supportedFamilies([.systemMedium])
}
}
预览效果:
特殊字体
利用 Text 定时器属性及图片制作成的特殊字体,不同的数字组合可以有不同的字符显示
实现也很简单,制作的字体添加到项目,后配置项目字体
在项目中直接使用
VStack() {
Text(entry.date, style: .time)
Text(Calendar.current.startOfDay(for: Date()), style: .timer)
.multilineTextAlignment(.center)
Text(Calendar.current.startOfDay(for: Date()), style: .timer)
.font(Font.custom("test-font-Regular", size: 30))
.multilineTextAlignment(.center)
}
clockHandRotationEffect(私有API)
因为用到 了私有API 有可能会被封,这里就不深入研究了,看下大佬们实现的效果
参考
本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。