कंटेंट पर जाएँ
charmotion

Live Activity, Dynamic Island और Widget एनिमेशन की सीमाएँ

Charmotion टीम द्वारा · अपडेट:

iOS और Swift गाइड का कवर इलस्ट्रेशन: Live Activity, Dynamic Island और Widget एनिमेशन की सीमाएँ, Charmotion डेमो कैरेक्टर के साथ

Live Activities, Dynamic Island और विजेट लगातार लूप होने वाला एनिमेशन नहीं चला सकते। iOS 17 से ये डेटा बदलने पर SwiftUI transitions और एनिमेशन से एनिमेट होते हैं, हर एक की सीमा दो सेकंड है, और Always-On डिस्प्ले पर कुछ भी एनिमेट नहीं होता। कैरेक्टर के लिए Rive, Lottie, GIF या वीडियो चलाने के बजाय, डेटा बदलने पर transition के साथ स्टैटिक पोज़ बदलें।

मुख्य बातें

  • Apple के WidgetKit docs: "विजेट और Live Activities में एनिमेशन की अधिकतम अवधि दो सेकंड है।"
  • Apple के एक DTS इंजीनियर ने कहा कि Dynamic Island और विजेट में लगातार चलने वाले एनिमेशन सपोर्ट नहीं होते, और timer-font वाली ट्रिक को एक unsupported hack बताया।
  • transition(_:), contentTransition(_:), animation(_:value:) और id(_:) इस्तेमाल करें; Transaction उपलब्ध नहीं है।
  • Live Activity का डेटा 4 KB तक सीमित है, और एक activity अधिकतम आठ घंटे तक सक्रिय रह सकती है।
  • अपने एनिमेशन सेट से स्टिल पोज़ एक्सपोर्ट करें और उन्हें विजेट extension में इमेज के रूप में शामिल करें।

क्या Live Activity या Dynamic Island लूप होने वाला कैरेक्टर एनिमेशन चला सकता है?

नहीं। विजेट और Live Activities को सिस्टम अपडेट के समय आपकी SwiftUI view hierarchy से render करता है; आपका कोड Lock Screen या Dynamic Island में कोई render loop नहीं चलाता। एनिमेशन सिर्फ़ एक render हुई स्टेट से अगली स्टेट तक के transition के रूप में होते हैं।

डेवलपर Apple के forums पर यह सवाल अक्सर पूछते हैं। Dynamic Island और विजेट को एनिमेट करने वाले एक thread में Apple के एक DTS इंजीनियर ने जवाब दिया कि "कुछ डेवलपर्स ने एक hack निकाला है, लेकिन सिस्टम उसे सपोर्ट नहीं करता और उसकी सिफ़ारिश नहीं की जा सकती", और यह भी कि दिखाए गए तरह का लगातार एनिमेशन "सपोर्ट नहीं होता और बैटरी जल्दी खत्म कर सकता है।" यह hack custom fonts के साथ timer text का गलत इस्तेमाल करके नकली फ़्रेम बनाता है; यह किसी भी release में टूट सकता है।

इसलिए Live Activity में मैस्कॉट idle नहीं रह सकता, न साँस लेता दिख सकता है, न पलक झपका सकता है। जब भी आपका ऐप या कोई push notification activity को अपडेट करे, तब यह छोटे एनिमेटेड transition के साथ अपना पोज़ बदल सकता है।

Notification badge के पास attention लूप में मैस्कॉट वाला फ़ोन

विजेट और Live Activities कौन से एनिमेशन सपोर्ट करते हैं?

Apple का लेख "Animating data updates in widgets and Live Activities" बताता है कि क्या काम करता है। iOS 17 से विजेट और Live Activities "सभी built-in SwiftUI transitions और animations सपोर्ट करते हैं।" पुराने OS वर्ज़न में विजेट एनिमेट नहीं होते, और iOS 16 या उससे पहले Live Activities animation modifiers को अनदेखा करके सिस्टम की टाइमिंग इस्तेमाल करती हैं, हालाँकि built-in transitions फिर भी लागू होते हैं।

सपोर्ट हैसपोर्ट नहीं है
text, images और SF Symbols पर डिफ़ॉल्ट content transitionsलगातार या बार-बार दोहराए जाने वाले एनिमेशन
transition(_:): opacity, move(edge:), slide, push(from:) और इनके कॉम्बिनेशनTransaction (इसलिए आप इससे एनिमेशन cancel नहीं कर सकते)
contentTransition(_:), जिसमें .numericText(countsDown:) भी शामिल हैदो सेकंड से लंबे एनिमेशन
animation(_:value:) और springsAlways-On low-luminance mode में कोई भी एनिमेशन
संबंधित डेटा बदलने पर view को एनिमेट करने के लिए id(_:)अपना render loop या timers चलाना

किसी view का एनिमेशन बंद करने के लिए Apple कहता है कि transition(_:) को .identity या animation(_:value:) को nil पास करें।

2 सेकंड की एनिमेशन सीमा क्या है?

WidgetKit documentation और Human Interface Guidelines का Live Activities सेक्शन, दोनों एक ही सीमा बताते हैं: विजेट और Live Activities में एनिमेशन की अधिकतम अवधि दो सेकंड है, चाहे वे सिस्टम एनिमेशन हों या custom।

व्यवहार में, हर ट्रांज़िशन को इस सीमा के अंदर आराम से पूरा होने के लिए डिज़ाइन करें। लंबे settle time वाला spring बीच में कट सकता है; .smooth(duration: 0.6) या .spring(duration: 0.5, bounce: 0.3) आराम से इस सीमा के भीतर रहते हैं। अगर कोई अपडेट कई views बदलता है, तो Apple सुझाव देता है कि कम ज़रूरी views पर एनिमेशन बंद कर दें, ताकि ध्यान मुख्य बदलाव पर जाए।

struct ScoreView: View {
    let score: Int

    var body: some View {
        Text(score, format: .number)
            .font(.title.monospacedDigit())
            .contentTransition(.numericText())
            .animation(.spring(duration: 0.5, bounce: 0.3), value: score)
    }
}

क्या मैं widget में GIF, Lottie, Rive या वीडियो चला सकता हूँ?

प्लेबैक के रूप में नहीं। सपोर्टेड तरीका SwiftUI के अपने transitions और एनिमेशन हैं, जिन्हें सिस्टम रेंडर करता है; ऐसे किसी player के लिए कोई hook नहीं है जो समय के साथ फ़्रेम आगे बढ़ाए। Rive और Lottie दोनों को एक लाइव render loop चाहिए, और widget या Live Activity यह नहीं देते। GIF और वीडियो प्लेबैक भी documented एनिमेशन मॉडल का हिस्सा नहीं हैं, और DTS ने लगातार चलने वाले एनिमेशन को unsupported बताया है।

इन assets के साथ आप जो कर सकते हैं, वह है इनमें से एक फ़्रेम इस्तेमाल करना। अपने कैरेक्टर के वीडियो से हर मूड के लिए एक still export करें और इमेज को widget extension के asset catalog में bundle करें। ffmpeg के साथ, अगर आप libvpx से decode करते हैं तो ट्रांसपेरेंट WebM का फ़्रेम अपना alpha बनाए रखता है:

ffmpeg -c:v libvpx-vp9 -i happy.webm -ss 1.0 -frames:v 1 mascot-happy.png
ffmpeg -c:v libvpx-vp9 -i loading.webm -ss 1.0 -frames:v 1 mascot-loading.png

पेड प्लान पर Charmotion सेट में सभी 17 एनिमेशन के ट्रांसपेरेंट WebM और MOV वर्ज़न शामिल हैं, इसलिए हर मूड और रिएक्शन इन स्थिर इमेज के सोर्स के रूप में उपलब्ध है। उन्हें उन पॉइंट साइज़ में रीसाइज़ करें जिनमें आप सच में दिखाते हैं; उदाहरण के लिए, Live Activity का मिनिमल प्रेज़ेंटेशन 45×36.67 पॉइंट से ज़्यादा नहीं होना चाहिए।

4 KB डेटा और आठ घंटे की सीमाएँ क्या हैं?

Apple के ActivityKit documentation, "Displaying live data with Live Activities" से:

सीमामान
हर अपडेट में static और dynamic डेटा (push payloads सहित)कुल मिलाकर 4 KB
Active रहने का समयअधिकतम आठ घंटे
Lock Screen पर कुल समयअधिकतम 12 घंटे (आठ घंटे active, और खत्म होने के बाद अधिकतम चार घंटे)
Minimal presentation image45×36.67 points से बड़ी नहीं
एनिमेशन की अवधिअधिकतम दो सेकंड

4 KB की सीमा के कारण इमेज कभी payload में नहीं भेजी जातीं। कोई छोटा मान भेजें, जैसे mood index, और bundled image खोजें:

import ActivityKit

struct DeliveryAttributes: ActivityAttributes {
    struct ContentState: Codable, Hashable {
        var mood: Int          // 0 idle, 5 loading, 1 happy ...
        var minutesLeft: Int
    }
    var orderNumber: String
}

HIG आगे बताता है कि Live Activities उन कामों के लिए सही हैं जो आठ घंटे से ज़्यादा नहीं चलते, और activity खत्म होने के बाद ज़्यादातर मामलों में Lock Screen पर 15 से 30 मिनट काफ़ी हैं।

Always-On display पर क्या होता है?

Always-On display वाले devices पर Apple कहता है कि "बैटरी बचाने के लिए Always On में सिस्टम एनिमेशन नहीं चलाता।" isLuminanceReduced environment value (iOS 16 और बाद के वर्ज़न) चेक करें और उसके अनुसार बदलाव करें: transition छोड़ दें और एक सरल, गहरा pose दिखाएँ।

struct MascotPose: View {
    @Environment(\.isLuminanceReduced) private var isLuminanceReduced
    let mood: Int

    var body: some View {
        Image("mascot-mood-\(mood)")
            .resizable()
            .scaledToFit()
            .opacity(isLuminanceReduced ? 0.6 : 1)
            .id(mood)
            .transition(isLuminanceReduced ? .identity : .push(from: .bottom))
    }
}

कम luminance वाला आर्टवर्क सरल रखें: dim Lock Screen पर बड़े चमकीले हिस्से चुभते हुए लगते हैं।

Live Activity में लूपिंग मैस्कॉट का सबसे अच्छा विकल्प क्या है?

Pose बदलना। हर मूड को एक still image मानें, और स्टेट बदलने पर सिस्टम को उनके बीच एनिमेट करने दें। जब कोई और डेटा बदले तब view को एनिमेट करने के लिए Apple का documented pattern है कि view को id(_:) के ज़रिए उस डेटा से जोड़ें और एक transition जोड़ें; यहाँ मूड ही identity है:

import SwiftUI
import WidgetKit

struct DeliveryLockScreenView: View {
    let state: DeliveryAttributes.ContentState

    var body: some View {
        HStack(spacing: 12) {
            MascotPose(mood: state.mood)
                .frame(width: 56, height: 56)
                .accessibilityHidden(true)
            VStack(alignment: .leading) {
                Text("Arriving in")
                    .font(.caption)
                HStack(alignment: .firstTextBaseline, spacing: 4) {
                    Text(state.minutesLeft, format: .number)
                        .contentTransition(.numericText(countsDown: true))
                    Text("min")
                }
                .font(.title2.bold())
            }
        }
        .padding()
    }
}

इसके बाद हर अपडेट एक छोटा, अर्थपूर्ण मोशन बनाता है: मिनट घटते रहते हैं और कैरेक्टर नए pose के साथ push होकर आता है। मूड को activity के phases से जोड़ें (तैयारी → loading pose, रास्ते में → happy, देरी → sad, डिलीवर हुआ → success pose), और आपको ऐसा कैरेक्टर मिलता है जो प्लेटफ़ॉर्म के नियम तोड़े बिना जीवंत लगता है। पूरे ऐप में असली एनिमेटेड कैरेक्टर इस्तेमाल करें; full-motion वर्ज़न की जगह वहीं है।

चार फ़ोन स्क्रीन, जिनमें मैस्कॉट loading, खाली inbox, पूरा हुआ पेमेंट और फ़ेल हुआ अपलोड दिखाता है
ऐप की चार सबसे आम स्टेट दिखाता एक मैस्कॉट।

अक्सर पूछे जाने वाले सवाल

क्या मैं timer-font trick से Dynamic Island को एनिमेट कर सकता हूँ?

ऐसा किया गया है, लेकिन एक Apple DTS engineer ने कहा कि यह तरीका सिस्टम द्वारा सपोर्टेड नहीं है, इसकी सिफ़ारिश नहीं की जा सकती, और लगातार चलने वाले एनिमेशन battery खत्म कर सकते हैं। यह किसी भी iOS अपडेट में टूट सकता है। इसके बजाय डेटा अपडेट के बीच सपोर्टेड transitions इस्तेमाल करें।

क्या iOS 16 पर widgets एनिमेट होते हैं?

नहीं। Apple के documentation के अनुसार iOS 17 से पहले के OS वर्ज़न में widgets एनिमेट नहीं होते। iOS 16 पर Live Activities animation(_:value:) जैसे animation modifiers को अनदेखा करती हैं और system timing इस्तेमाल करती हैं, लेकिन opacity, move, slide और push जैसे built-in transitions फिर भी लागू होते हैं।

क्या मैं Live Activity push में मैस्कॉट इमेज भेज सकता हूँ?

व्यावहारिक रूप से नहीं। Live Activity का सारा static और dynamic डेटा, push payloads सहित, कुल मिलाकर 4 KB में आना चाहिए। Pose इमेज को widget extension में bundle करें और सिर्फ़ एक छोटी वैल्यू भेजें, जैसे मूड नंबर, जो तय करे कि कौन-सी इमेज दिखानी है।

Widget या Live Activity का एनिमेशन कितनी देर चल सकता है?

अधिकतम दो सेकंड। Apple का WidgetKit documentation और Live Activities Human Interface Guidelines, दोनों बताते हैं कि widgets और Live Activities में system और custom एनिमेशन की अधिकतम अवधि दो सेकंड है। Springs और transitions को इससे आराम से छोटा रखें ताकि वे मोशन के बीच में न कटें।

इस गाइड से झटपट जवाब

स्रोत

संबंधित गाइड