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

iOS WidgetKit中显示Lottie动画:APP代码在组件中失效问题

在WidgetKit中显示Lottie动画的问题与解决方案

问题描述

我尝试在iOS WidgetKit中显示Lottie动画,使用了Airbnb的lottie-ios库,该库在APP中运行正常,但相同代码在WidgetKit中无法生效。

APP中可正常运行的代码

struct widgetTestyView : View {
    var body: some View {
        VStack() {
            LottieView(animation: LottieAnimation.named("Samples/9squares_AlBoardman")!)
        }
    }
}

WidgetKit中无法生效的代码

//
//  widget.swift
//  widget
//

import WidgetKit
import SwiftUI
import Lottie

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date())
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date())
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate)
            entries.append(entry)
        }

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

struct SimpleEntry: TimelineEntry {
    let date: Date
}

struct widgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        VStack() {
            LottieView(animation: LottieAnimation.named("Samples/9squares_AlBoardman")!)
        }
    }
}

@main
struct widget: Widget {
    let kind: String = "widget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            widgetEntryView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

struct widget_Previews: PreviewProvider {
    static var previews: some View {
        widgetEntryView(entry: SimpleEntry(date: Date()))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

请问是否可以在WidgetKit中显示Lottie动画?


解决方案

可以在WidgetKit中显示Lottie动画,但WidgetKit有严格的渲染和性能限制,常规的LottieView无法直接适配,需要调整实现方式:

1. 使用UIViewRepresentable封装Lottie动画视图

WidgetKit对SwiftUI自定义视图支持有限,需要用UIViewRepresentable封装原生LottieAnimationView,适配Widget渲染规则:

struct LottieWidgetView: UIViewRepresentable {
    let animationName: String
    
    func makeUIView(context: Context) -> LottieAnimationView {
        let animationView = LottieAnimationView(name: animationName)
        animationView.contentMode = .scaleAspectFit
        animationView.loopMode = .loop
        animationView.play()
        return animationView
    }
    
    func updateUIView(_ uiView: LottieAnimationView, context: Context) {
        // Widget刷新时重启未播放的动画
        if !uiView.isAnimationPlaying {
            uiView.play(fromProgress: 0)
        }
    }
}

2. 修正资源引用路径

确保Lottie的JSON动画文件已添加到Widget的target中,不要使用相对路径(如Samples/),直接使用文件名即可——Widget的bundle资源路径与APP独立。

3. 适配Widget生命周期

Widget基于Timeline刷新,动画不会自动持续播放。若需要循环或触发动画,可调整Timeline刷新频率,或在updateUIView中根据Entry状态控制动画播放逻辑。

4. 优化动画性能

复杂的Lottie动画可能被WidgetKit限制播放,建议:

  • 使用简化的动画文件,减少图层和关键帧数量
  • 降低动画速度(如设置animationView.animationSpeed = 0.5)
  • 避免高透明度、复杂渐变等性能消耗大的效果

修改后的WidgetEntryView示例

struct widgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        VStack() {
            LottieWidgetView(animationName: "9squares_AlBoardman")
                .frame(width: 80, height: 80)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:43:13