2012-05-30 11 views
10

मैं एक रिमोट अधिसूचना आने पर 5s के लिए स्क्रीन पर एक कस्टम UIView प्रदर्शित करने की कोशिश कर रहा हूं।जीसीडी के साथ 'धारावाहिक' एनीमेशन कैसे करें?

कोड इस तरह:

//customView.alpha = 1.0 here 
[UIView animateWithDuration:1 animations:^{ 
            customView.alpha = 0.3; 
           } 
           completion:^(BOOL finished){ 
            // remove customView from super view. 
           }]; 

समस्या और क्या मैं आवश्यकता

लेकिन कर रहे हैं मामले कि अधिसूचना की एक जोड़ी, कम समय के अंतराल पर आ सकता है, जिसमें कई customView हो सकता है एक ही समय में एनिमेटिंग हो और कोई दूसरों को कवर कर सकता है।

मैं चाहता हूं कि ये एनिमेशन एक के बाद एक प्रदर्शन करें, ताकि वे संघर्ष न करें।

ग्रहण लेकिन विफल

//(dispatch_queue_t)queue was created in other parts of the code 
dispatch_sync(queue, ^{ 
    [UIView animationWithDuration:animations:...]; 
}); 

GCD कतार में एनीमेशन करने के बाद, मैं मूल कोड मैं प्रयोग किया जाता है, जो GCD का उपयोग नहीं किया रूप में एक ही परिणाम मिला। एनिमेशन अभी भी विरोधाभासी हैं।

BTW, मैंने सुना है कि एनिमेशन या कार्यों यूआई शामिल हमेशा मुख्य थ्रेड पर चलते जाना चाहिए, लेकिन मेरी दूसरी कोड में एनीमेशन ठग किया लग रहा था। क्यूं कर?

उत्तर

4

यदि यह वही एनीमेशन है जो हर बार चलता है तो आप एनीमेशन को चलाने की संख्या को कितनी बार स्टोर कर सकते हैं (एनीमेशन की दोहराने वाली गिनती संपत्ति के समान नहीं)।

जब आपको रिमोट अधिसूचना मिलती है तो आप काउंटर को बढ़ाते हैं और उस विधि को कॉल करते हैं जो काउंटर बिल्कुल सही है। फिर विधि में क्या आप हर बार काउंटर को कम करते हुए पूर्ण रूप से समापन ब्लॉक में स्वयं को कॉल करते हैं।यह (स्यूडोकोड विधि के नाम के साथ) कुछ इस तरह दिखेगा:

- (void)methodThatIsRunWhenTheNotificationIsReceived { 
    // Do other stuff here I assume... 
    self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation + 1; 
    if ([self.numberOfTimesToRunAnimation == 1]) { 
     [self methodThatAnimates]; 
    } 
} 

- (void)methodThatAnimates { 
    if (self.numberOfTimesToRunAnimation > 0) { 
     // Animation preparations ... 
     [UIView animateWithDuration:1 
         animations:^{ 
            customView.alpha = 0.3; 
         } 
         completion:^(BOOL finished){ 
            // Animation clean up ... 
            self.numberOfTimesToRunAnimation = self.numberOfTimesToRunAnimation - 1; 
            [self methodThatAnimates]; 
         }]; 
    } 
} 
+1

आपके पास @Ducan जैसा ही विचार है। आपके कोड के लिए धन्यवाद। और क्या आपको लगता है कि हमें 'self.numberOfTimesToRunAnimation' लॉक करना चाहिए? – studyro

+0

हां। संपत्ति को "nonatomic" के रूप में परिभाषित नहीं करते हैं और कभी भी चर का उपयोग नहीं करते (हमेशा संपत्ति का उपयोग करते हुए) सिस्टम आपके लिए वैरिएबल को लॉक कर देगा ताकि दो थ्रेड एक ही समय में इसे पढ़/लिख न सकें। –

+0

बहुत अच्छा। मैंने खंडित नियंत्रण यूआई को नियंत्रित करने के लिए इसका इस्तेमाल किया। 'चयनित इंडेक्स' को संपत्ति में डालकर, इसे पूरा करने पर इसे 'NSNotFound' पर सेट करके, मुझे एनीमेशन के दौरान नियंत्रण को अक्षम करने की आवश्यकता नहीं है। धन्यवाद! –

0

मैं एनीमेशन को ट्रिगर करने वाली किसी भी वस्तु को पूरा करने के ब्लॉक में एक संदेश भेजने का सुझाव दूंगा। फिर आप उस ऑब्जेक्ट को अधिसूचनाओं को स्वयं कतारबद्ध कर सकते हैं और अगली बार संदेश प्राप्त करते समय अगली बार शुरू कर सकते हैं।

1

आप इस्तेमाल कर सकते हैं एक (गैर) समवर्ती NSOperationQueue

NSOperationQueue वर्ग NSOperation वस्तुओं का एक सेट के निष्पादन को नियंत्रित करता है "कदम से कदम" एनिमेशन प्रदर्शन करने के लिए। कतार में जोड़े जाने के बाद, उस कतार में एक ऑपरेशन तब तक बना रहता है जब तक कि इसे स्पष्ट रूप से रद्द नहीं किया जाता है या अपने कार्य को निष्पादित नहीं किया जाता है। कतार के भीतर संचालन (लेकिन अभी तक निष्पादित नहीं) खुद को प्राथमिकता स्तर और अंतर-संचालन वस्तु निर्भरताओं के अनुसार व्यवस्थित किया जाता है और तदनुसार निष्पादित किया जाता है। एक आवेदन कई ऑपरेशन कतार बना सकता है और उनमें से किसी के लिए संचालन जमा कर सकता है।

इंटर-ऑपरेशन निर्भरता संचालन के लिए एक पूर्ण निष्पादन आदेश प्रदान करती है, भले ही वे ऑपरेशन अलग-अलग ऑपरेशन कतारों में स्थित हों। एक ऑपरेशन ऑब्जेक्ट को पर निष्पादित नहीं माना जाता है जब तक कि इसके सभी निर्भर संचालन निष्पादित नहीं हो जाते हैं। निष्पादित करने के लिए तैयार संचालन के लिए, ऑपरेशन कतार हमेशा अन्य तैयार संचालन के सापेक्ष उच्चतम प्राथमिकता वाले व्यक्ति को निष्पादित करता है।

+1

एनिमेट विथ अवधि: ... असीमित है। यह समस्या को कैसे हल करेगा? एनीमेशन पूर्ण होने से पहले प्रत्येक ऑपरेशन तुरंत खत्म हो जाएगा। –

+0

एनीमेशन पर समापन ब्लॉक में isfinished संपत्ति सेट करें। दस्तावेज़ों से: "परिभाषित कुंजी पथ ग्राहकों को यह बताता है कि एक ऑपरेशन ने अपना कार्य सफलतापूर्वक समाप्त कर दिया था या रद्द कर दिया गया था और बाहर निकल रहा है।" – CarlJ

4

अनुक्रम में एनिमेशन प्रस्तुत करने के लिए काम नहीं करेगा कतारों का उपयोग करना, क्योंकि विधि है कि एनीमेशन रिटर्न तुरंत शुरू होता है, और एनीमेशन एनीमेशन में जोड़ा जाता है पेड़ बाद में किया जाना है। आपकी कतार में प्रत्येक प्रविष्टि एक सेकंड के एक छोटे से हिस्से में पूरा हो जाएगा।

यदि आपकी प्रत्येक एनिमेशन एक ही दृश्य पर चलती है तो डिफ़ॉल्ट रूप से सिस्टम को प्रत्येक एनीमेशन को अगले एक से पहले चलने से पहले चलाना चाहिए।

UIViewAnimationOptionBeginFromCurrentState विकल्पों मूल्य के लिए डॉक्स के शब्दों में:

UIViewAnimationOptionBeginFromCurrentState

एनीमेशन से वर्तमान एक पहले से ही उड़ान में एनीमेशन के साथ जुड़े सेटिंग शुरू करो। यदि यह कुंजी मौजूद नहीं है, तो नई एनीमेशन शुरू होने से पहले किसी भी इन-फ्लाइट एनिमेशन को समाप्त करने की अनुमति है। यदि कोई और एनीमेशन उड़ान में नहीं है, तो इस कुंजी का कोई प्रभाव नहीं पड़ता है।

आप श्रृंखला के लिए एनिमेशन की एक श्रृंखला चाहते हैं, यहाँ मैं क्या कर सकता है:

एनीमेशन ब्लॉक के एक परिवर्तनशील सरणी बनाएँ। (कोड ब्लॉक ऑब्जेक्ट्स हैं, और एक सरणी में जोड़ा जा सकता है।) एक विधि लिखें जो शीर्ष एनीमेशन ब्लॉक को सरणी से खींचती है (और इसे सरणी से हटा देती है) और इसे एनिमेटथिथेशन: एनीमेशन का उपयोग करके सबमिट करता है: पूर्णता, जहां पूरा करने की विधि बस विधि फिर से आमंत्रित करता है। कोड को सरणी से किसी आइटम को खींचने से पहले लॉक पर जोर दें, और आइटम को हटाने के बाद लॉक को मुक्त करें।

फिर आप कोड लिख सकते हैं जो आपके एनीमेशन सरणी लॉक पर जोर देकर, आने वाली अधिसूचना का जवाब देता है, लॉक में एनीमेशन ब्लॉक जोड़ता है, और लॉक जारी करता है।

+0

धन्यवाद! मुझे लगता है कि मुझे जो चाहिए वह करने का यह सही तरीका है। – studyro

0

ProcedureKit (NSOperation पर आधारित) तैयार किए गए समाधान का एक उदाहरण है, लेकिन यह केवल एनिमेशन के लिए इसका उपयोग करने के लिए काफी हेवीवेट है।

मेरे Operation उपवर्ग जो मैं एनिमेटेड पॉप-अप और अन्य सामग्री क़तार में उपयोग करें:

class SerialAsyncOperation: Operation { 

    private var _started = false 

    private var _finished = false { 
     willSet { 
      guard _started, newValue != _finished else { 
       return 
      } 
      willChangeValue(forKey: "isFinished") 
     } 
     didSet { 
      guard _started, oldValue != _finished else { 
       return 
      } 
      didChangeValue(forKey: "isFinished") 
     } 
    } 

    private var _executing = false { 
     willSet { 
      guard newValue != _executing else { 
       return 
      } 
      willChangeValue(forKey: "isExecuting") 
     } 
     didSet { 
      guard oldValue != _executing else { 
       return 
      } 
      didChangeValue(forKey: "isExecuting") 
     } 
    } 

    override var isAsynchronous: Bool { 
     return true 
    } 

    override var isFinished: Bool { 
     return _finished 
    } 

    override var isExecuting: Bool { 
     return _executing 
    } 

    override func start() { 
     guard !isCancelled else { 
      return 
     } 
     _executing = true 
     _started = true 
     main() 
    } 

    func finish() { 
     _executing = false 
     _finished = true 
    } 

    override func cancel() { 
     _executing = false 
     _finished = true 
     super.cancel() 
    } 
} 

उपयोग के उदाहरण:

// Setup a serial queue 
private lazy var serialQueue: OperationQueue = { 
    let queue = OperationQueue() 
    queue.maxConcurrentOperationCount = 1 
    queue.name = String(describing: type(of: self)) 
    return queue 
}() 

// subclass SerialAsyncOperation 
private class MessageOperation: SerialAsyncOperation { 

    // ... 

    override func main() { 
     DispatchQueue.main.async { [weak self] in 
      // do UI stuff 

      self?.present(completion: { 
       self?.finish() 
      }) 
     } 
    } 

    func present(completion: @escaping() -> Void) { 
     // do async animated presentation, calling completion() in its completion 
    } 

    func dismiss(completion: @escaping() -> Void) { 
     // do async animated dismissal, calling completion() in its completion 
    } 

    // animated cancellation support 
    override func cancel() { 
     if isExecuting { 
      dismiss(completion: { 
       super.cancel() 
      }) 
     } else { 
      super.cancel() 
     } 
    } 
} 

मूल रूप से, सिर्फ इस आपरेशन एक सीरियल कतार में जोड़ने के लिए, और जब आप अपनी असीमित सामग्री को पूरा करते हैं तो finish() पर कॉल करना याद रखें। इसके अलावा आप एक कॉल के साथ सीरियल कतार पर सभी परिचालनों को रद्द कर सकते हैं, और इन्हें शानदार तरीके से खारिज कर दिया जाएगा।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^