【iOS小组件】自定义小组件动画

746 阅读2分钟

前言


前面了解了 Text 相关的过渡动画,这两天了解到小组件也是可以展示动画的。在 iOS 17 之前动画一直是被禁用的,但是仍有人在小组件上实现了动画效果,这里记录一下小组件实现动画的几种方式。

帧动画


利用小组件的时间线机制,每秒调用一次 reloadAllTimelines 方法刷新UI来达到动画效果,如下效果(如需查看源码请看参考链接):

11.gif

我们也可以借此思路实现一个简版时钟,代码如下

//  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])
    }
}

预览效果:

22.gif

特殊字体


利用 Text 定时器属性及图片制作成的特殊字体,不同的数字组合可以有不同的字符显示

image.png

实现也很简单,制作的字体添加到项目,后配置项目字体

image.png

在项目中直接使用

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)
}

33.gif

clockHandRotationEffect(私有API)

因为用到 了私有API 有可能会被封,这里就不深入研究了,看下大佬们实现的效果

图片

图片

图片

图片

参考

本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。