You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS16 WidgetKit如何实现时钟Widget秒针跳跃式动画?

在WidgetKit中实现秒针跳跃式运动(Jumping Motion)

要实现秒针每秒跳动一次的效果,不能依赖_ClockHandRotationEffect的连续动画,而是需要通过每秒更新状态+触发即时过渡动画的方式来实现,具体方案如下:

核心思路

  1. 让Widget的Timeline每秒刷新一次,传递当前精确的秒数状态
  2. 根据当前秒数计算秒针应处的旋转角度(每秒钟对应6度,360/60)
  3. 使用SwiftUI的animation修饰符,在状态更新时触发瞬间完成的跳跃动画,替代连续旋转效果

代码实现示例

1. 定义Widget的时间数据模型

struct ClockEntry: TimelineEntry {
    let date: Date
    let seconds: Int
}

2. 实现TimelineProvider,每秒生成一个Entry

struct ClockTimelineProvider: TimelineProvider {
    func placeholder(in context: Context) -> ClockEntry {
        ClockEntry(date: Date(), seconds: Calendar.current.component(.second, from: Date()))
    }

    func getSnapshot(in context: Context, completion: @escaping (ClockEntry) -> ()) {
        let now = Date()
        completion(ClockEntry(date: now, seconds: Calendar.current.component(.second, from: now)))
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<ClockEntry>) -> ()) {
        var entries: [ClockEntry] = []
        let currentDate = Date()
        
        // 生成接下来60秒的Entry,每秒一个
        for secondOffset in 0..<60 {
            let entryDate = Calendar.current.date(byAdding: .second, value: secondOffset, to: currentDate)!
            let seconds = Calendar.current.component(.second, from: entryDate)
            entries.append(ClockEntry(date: entryDate, seconds: seconds))
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

3. 构建秒针View,实现跳跃式旋转

struct ClockWidgetView: View {
    var entry: ClockTimelineProvider.Entry
    
    private var secondHandRotation: Angle {
        // 每秒钟旋转6度(360/60)
        Angle(degrees: Double(entry.seconds) * 6)
    }
    
    var body: some View {
        ZStack {
            // 时钟背景(示例)
            Circle()
                .stroke(Color.gray, lineWidth: 2)
            
            // 秒针
            Rectangle()
                .fill(Color.red)
                .frame(width: 2, height: 80)
                .offset(y: -40)
                .rotationEffect(secondHandRotation)
                // 使用.interactiveSpring实现带轻微弹跳的跳秒效果,替换为.instant可实现生硬跳跃
                .animation(.interactiveSpring(response: 0.1, dampingFraction: 0.8), value: entry.seconds)
        }
        .frame(width: 150, height: 150)
    }
}

4. 配置Widget

struct ClockWidget: Widget {
    let kind: String = "ClockWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: ClockTimelineProvider()) { entry in
            ClockWidgetView(entry: entry)
        }
        .configurationDisplayName("跳跃式秒针时钟")
        .description("每秒跳动一次的秒针Widget")
        .supportedFamilies([.systemSmall])
    }
}

关键说明

  • 动画曲线选择:.interactiveSpring能模拟系统原生跳秒时钟的轻微弹跳质感,若需要完全无过渡的生硬跳跃,可替换为.instant
  • 刷新策略:通过生成60个每秒的Entry,保证Widget能持续连贯地更新秒针状态
  • 安全性:方案全程使用公开API,避免了私有API_ClockHandRotationEffect带来的审核风险

内容的提问来源于stack exchange,提问作者mars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:53:12