অ্যানিমেশনডিসটপ ডেলিগেটের মধ্যে সিএএনিমেশন কীভাবে চিহ্নিত করবেন?


102

আমার একটি সমস্যা ছিল যেখানে আমার ক্রমবর্ধমান ক্যাটারানসিশন / সিএএনিমেশন সিকোয়েন্সগুলির একটি সিরিজ ছিল, এনিমেশনগুলি বন্ধ হয়ে গেলে আমার সমস্ত কাস্টম অপারেশন করা দরকার ছিল, তবে আমি কেবলমাত্র অ্যানিমেশনডিসটপের জন্য একটি প্রতিনিধি হ্যান্ডলার চেয়েছিলাম।

তবে, আমার একটি সমস্যা ছিল, অ্যানিমেশনডিসটপ ডেলিগ্রেটে প্রতিটি ক্যাটারানসিশন / সিএএনিমেশন স্বতন্ত্রভাবে চিহ্নিত করার উপায় বলে মনে হয় নি।

আমি CAAnimation এর অংশ হিসাবে উন্মুক্ত কী / মান সিস্টেমের মাধ্যমে এই সমস্যাটি সমাধান করেছি।

আপনি যখন অ্যানিমেশনটি শুরু করেন যখন অ্যানিমেশনডিসটপ আগুন জ্বলতে থাকে তখন সনাক্তকারী এবং মানগুলি সেট করতে CATransition / CAAnimation এ সেটভ্যালু পদ্ধতিটি ব্যবহার করুন:

-(void)volumeControlFadeToOrange
{   
    CATransition* volumeControlAnimation = [CATransition animation];
    [volumeControlAnimation setType:kCATransitionFade];
    [volumeControlAnimation setSubtype:kCATransitionFromTop];
    [volumeControlAnimation setDelegate:self];
    [volumeControlLevel setBackgroundImage:[UIImage imageNamed:@"SpecialVolume1.png"] forState:UIControlStateNormal];
    volumeControlLevel.enabled = true;
    [volumeControlAnimation setDuration:0.7];
    [volumeControlAnimation setValue:@"Special1" forKey:@"MyAnimationType"];
    [[volumeControlLevel layer] addAnimation:volumeControlAnimation forKey:nil];    
}

- (void)throbUp
{
    doThrobUp = true;

    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionFade];
    [animation setSubtype:kCATransitionFromTop];
    [animation setDelegate:self];
    [hearingAidHalo setBackgroundImage:[UIImage imageNamed:@"m13_grayglow.png"] forState:UIControlStateNormal];
    [animation setDuration:2.0];
    [animation setValue:@"Throb" forKey:@"MyAnimationType"];
    [[hearingAidHalo layer] addAnimation:animation forKey:nil];
}

আপনার অ্যানিমেশনডিডস্টপ প্রতিনিধিতে:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{

    NSString* value = [theAnimation valueForKey:@"MyAnimationType"];
    if ([value isEqualToString:@"Throb"])
    {
       //... Your code here ...
       return;
    }


    if ([value isEqualToString:@"Special1"])
    {
       //... Your code here ...
       return;
    }

    //Add any future keyed animation operations when the animations are stopped.
 }

এর অন্য দিকটি হ'ল এটি আপনাকে আপনার প্রতিনিধি শ্রেণিতে এটি সংরক্ষণ করার পরিবর্তে মূল মান জোড় পদ্ধতিতে রাষ্ট্র রাখতে দেয় keep যত কম কোড, তত ভাল।

কী মান জোড় কোডিংয়ের জন্য অ্যাপল রেফারেন্সটি পরীক্ষা করে দেখুন ।

অ্যানিমেশনডিডস্টপ প্রতিনিধিতে CAAnimation / CATransition সনাক্তকরণের জন্য আরও ভাল কৌশল আছে?

ধন্যবাদ, - ব্যাটগার


4
বাটগার, যখন আমি "আইফোন অ্যানিমেশনডিডস্টপ আইডেন্টিফ" সনাক্ত করি, তখন প্রথম হিটটি ছিল আপনার পোস্ট, অ্যানিমেশনটি সনাক্ত করতে কী-মান ব্যবহার করার পরামর্শ দিয়েছিল। আমার যা প্রয়োজন, ধন্যবাদ। রুডি
রুদিফা

1
সচেতন যে হতে CAAnimationএর delegateতাই আপনি এটি সেট করতে করতে হতে পারে, শক্তিশালী nilচক্র ধরে রাখা এড়িয়ে যাচ্ছেন!
আইউলিয়ান ওনোফ্রেই

উত্তর:


92

বাটগার কৌশলটি খুব জটিল। কেন addAnimation এ forKey প্যারামিটারের সুবিধা নিবেন না? এটি এই খুব উদ্দেশ্যে উদ্দেশ্যে করা হয়েছিল। কেবল সেটভ্যালুতে কলটি বের করুন এবং কী স্ট্রিংটিকে অ্যাডঅ্যানিমেশন কলটিতে সরান। উদাহরণ স্বরূপ:

[[hearingAidHalo layer] addAnimation:animation forKey:@"Throb"];

তারপরে, আপনার অ্যানিমেশনডিসটপ কলব্যাকে, আপনি এর মতো কিছু করতে পারেন:

if (theAnimation == [[hearingAidHalo layer] animationForKey:@"Throb"]) ...

আমি উল্লেখ করতে চাই যে উপরের ইনক্রিমেন্টগুলি পুনরায় ব্যবহার করুন! সতর্কাবস্থা. এটি হ'ল অ্যানিমেশনফোরকি: আপনার CAAnimation অবজেক্টের রক্ষণ গণনা বৃদ্ধি করে।
মিমিলো

1
@ মিমিলো এটি খুব বেশি উদ্বৃত্ত নয়, তাই না? একটি স্তরে একটি অ্যানিমেশন যুক্ত করে, স্তরটি অ্যানিমেশনের মালিক, সুতরাং অ্যানিমেশনের ধরে রাখার গণনা অবশ্যই বর্ধিত।
গরিলাপ্যাচ

16
কাজ করে না - স্টপ সিলেক্টর বলা হওয়ার সাথে সাথে অ্যানিমেশনটি আর বিদ্যমান নেই। আপনি একটি নাল রেফারেন্স পাবেন।
অ্যাডাম

4
এটি ফোরকি: প্যারামিটারের অপব্যবহার এবং এটির কোনও প্রয়োজন নেই। বাটগার যা করছেন তা হুবহু - কী-মান কোডিং আপনাকে আপনার অ্যানিমেশনটিতে যেকোন স্বেচ্ছাচারিত ডেটা সংযুক্ত করতে দেয়, যাতে আপনি সহজেই এটি সনাক্ত করতে পারেন।
ম্যাট

7
অ্যাডাম, নীচে জিমটির উত্তর দেখুন - আপনাকে অবশ্যই সেট করতে হবে anim.removedOnCompletion = NO;যাতে -animationDidStop:finished:ডাকে যখন এটি এখনও উপস্থিত থাকে ।
ইয়াং মায়ার

46

আমি স্রেফ সিএএনিমেশনগুলির জন্য সমাপ্তির কোডটি করার আরও একটি ভাল উপায় নিয়ে এসেছি:

আমি একটি ব্লকের জন্য একটি টাইপডেফ তৈরি করেছি:

typedef void (^animationCompletionBlock)(void);

এবং একটি কী যা আমি অ্যানিমেশনটিতে একটি ব্লক যুক্ত করতে ব্যবহার করি:

#define kAnimationCompletionBlock @"animationCompletionBlock"

তারপরে, যদি আমি সিএএনিমেশন শেষ হওয়ার পরে অ্যানিমেশন সমাপ্তির কোডটি চালাতে চাই, আমি নিজেকে অ্যানিমেশনের প্রতিনিধি হিসাবে সেট করব এবং সেটভ্যালু: ফোরকি ব্যবহার করে অ্যানিমেশনে কোডের একটি ব্লক যুক্ত করব:

animationCompletionBlock theBlock = ^void(void)
{
  //Code to execute after the animation completes goes here    
};
[theAnimation setValue: theBlock forKey: kAnimationCompletionBlock];

তারপরে, আমি একটি অ্যানিমেশনডিডস্টপ: সমাপ্ত: পদ্ধতিটি প্রয়োগ করি, যা নির্দিষ্ট কীতে কোনও ব্লকের জন্য পরীক্ষা করে এবং যদি এটি পাওয়া যায় তবে কার্যকর করে:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
  animationCompletionBlock theBlock = [theAnimation valueForKey: kAnimationCompletionBlock];
  if (theBlock)
    theBlock();
}

এই পদ্ধতির সৌন্দর্য হ'ল আপনি অ্যানিমেশন বস্তুটি যেখানে তৈরি করেছেন সেখানে ক্লিনআপ কোডটি লিখতে পারেন। আরও ভাল, কোডটি যেহেতু একটি ব্লক, তাই এর সংযুক্তি স্কোপটিতে এটির স্থানীয় ভেরিয়েবলগুলিতে অ্যাক্সেস রয়েছে যা এটি সংজ্ঞায়িত হয়েছে। ইউজারআইফোনো ডিকশনারি বা এ জাতীয় অন্যান্য বাজে কথা সেটআপ করতে আপনাকে গণ্ডগোলের দরকার নেই, এবং একটি ক্রমবর্ধমান অ্যানিমেশন লিখতে হবে না ডিডসটপ: সমাপ্ত: এমন পদ্ধতি যা আপনি বিভিন্ন ধরণের অ্যানিমেশন যুক্ত করার সাথে সাথে আরও জটিল হয়ে ওঠে।

সত্যই বলা যেতে পারে, CAAnimation এর মধ্যে একটি সমাপ্তি ব্লক সম্পত্তি থাকা উচিত এবং এটি নির্দিষ্ট করা থাকলে স্বয়ংক্রিয়ভাবে কল করার জন্য সিস্টেম সমর্থন থাকতে হবে support তবে উপরের কোডটি আপনাকে কয়েকটি কোডের অতিরিক্ত কোডের সাথে একই কার্যকারিতা দেয়।


7
কেউ এর জন্য CAAnimation এ একটি বিভাগও রেখেছিলেন: github.com/xissburg/CAAnimationBlocks
জে পিয়ের

এটি সঠিক বলে মনে হচ্ছে না। বেশিরভাগ ক্ষেত্রে, আমি অনুরোধ করা হওয়ার ঠিক পরেই একটি EXEC_Err theBlock();পাই, এবং আমি বিশ্বাস করি এটি ব্লকের পরিধিটি ধ্বংস হওয়ার কারণে হয়েছে।
মাহবুডজ

আমি কিছুক্ষণের জন্য ব্লকটি ব্যবহার করছি এবং এটি অ্যাপলের ভয়ানক "অফিসিয়াল" পদ্ধতির চেয়ে অনেক বেশি ভাল কাজ করে।
আদম

3
আমি মোটামুটি নিশ্চিত যে কোনও সম্পত্তির মূল্য হিসাবে সেট করার আগে আপনাকে সেই ব্লক [ব্লক অনুলিপি] করতে হবে।
ফিয়োনা হপকিন্স

1
না, আপনার ব্লকটি অনুলিপি করার দরকার নেই।
ডানকান সি

33

দ্বিতীয় পদ্ধতির আপনি স্পষ্টভাবে আপনার অ্যানিমেশন সেট যদি শুধু কাজ করবে না এটা চালানোর আগে সমাপ্ত অপসারণ করা:

CAAnimation *anim = ...
anim.removedOnCompletion = NO;

আপনি যদি এটি করতে ব্যর্থ হন তবে আপনার অ্যানিমেশনটি শেষ হওয়ার আগেই সরিয়ে ফেলা হবে, এবং কলব্যাক অভিধানে এটি খুঁজে পাবে না।


10
এটি একটি মন্তব্য হওয়া উচিত, উত্তর নয়।
পর্যন্ত

2
আমি অবাক হয়েছি যে এটি মুছে ফেলার পরে মুছে ফেলা দরকার?
bompf

এটি আপনি যা করতে চান তা নির্ভর করে। আপনি প্রয়োজনে এটি অপসারণ করতে পারেন বা এটিকে ছেড়ে দিতে পারেন কারণ আপনি অন্য কোনও কিছু করতে চান।
আপেলজ্যাক 42

31

অন্যান্য সমস্ত উত্তর উপায় খুব জটিল! অ্যানিমেশনটি সনাক্ত করতে আপনি কেবল নিজের চাবিটি যুক্ত করবেন না কেন?

এই সমাধানটি আপনার পক্ষে খুব সহজে আপনার অ্যানিমেশনটিতে নিজের কী যুক্ত করা দরকার (উদাহরণস্বরূপ অ্যানিমেশনআইডি)

অ্যানিমেশন 1 চিহ্নিত করতে এই লাইনটি সন্নিবেশ করুন :

[myAnimation1 setValue:@"animation1" forKey:@"animationID"];

এবং এটি অ্যানিমেশন 2 সনাক্ত করতে :

[myAnimation2 setValue:@"animation2" forKey:@"animationID"];

এটি পরীক্ষা করুন:

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
    if([[animation valueForKey:@"animationID"] isEqual:@"animation1"]) {
    //animation is animation1

    } else if([[animation valueForKey:@"animationID"] isEqual:@"animation2"]) {
    //animation is animation2

    } else {
    //something else
    }
}

এটির জন্য কোনও উদাহরণ ভেরিয়েবলের প্রয়োজন হয় না :


আমি অ্যানিমেশনটিতে কিছু [animation valueForKey:@"animationID"]
অন্তর্নির্মিত

14

উপরে থেকে কী বোঝানো হয়েছে তা স্পষ্ট করে তোলার জন্য (এবং কয়েকটা নষ্ট ঘন্টা পরে কী আমাকে এখানে এনেছে): আপনি যে মূল অ্যানিমেশন বস্তুটি বরাদ্দ করেছিলেন তা আপনার কাছে ফিরে যাওয়ার আশা করবেন না

 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag 

যখন অ্যানিমেশনটি শেষ হয়, কারণ [CALayer addAnimation:forKey:]আপনার অ্যানিমেশনটির একটি অনুলিপি তৈরি করে।

আপনি যেটির উপর নির্ভর করতে পারেন, তা হ'ল animationDidStop:finished:বার্তাটি দিয়ে যাওয়া প্রতিরূপ অ্যানিমেশন অবজেক্টটিতে আপনার অ্যানিমেশন বস্তুকে যে মূল মানগুলি দেওয়া হয়েছিল সেগুলি এখনও সমান মান (তবে প্রয়োজনীয় পয়েন্টার সমতুল্য নয়) রয়েছে । উপরে উল্লিখিত হিসাবে, কেভিসি ব্যবহার করুন এবং আপনি স্টোর সংরক্ষণ এবং পুনরুদ্ধার করার যথেষ্ট সুযোগ পাবেন।


1
+1 এটি সেরা সমাধান! আপনি এর সাথে অ্যানিমেশনের 'নাম' [animation setValue:@"myanim" forKey:@"name"]সেট করতে পারেন এবং আপনি এমনকি স্তরটি ব্যবহার করে অ্যানিমেটেড সেট করতে পারেন [animation setValue:layer forKey:@"layer"]। এই মানগুলি ডেলিগেট পদ্ধতিতে পুনরুদ্ধার করা যেতে পারে।
ট্রোজানফো

valueForKey:nilআমার জন্য ফিরে , কোন ধারণা কেন?
আইলিয়ান ওনোফ্রেই

@ আইলিয়ানঅনফ্রেই পরীক্ষা করে দেখুন যে আপনার অ্যানিমেশনটি একই সম্পত্তির জন্য অন্য অ্যানিমেশন দ্বারা স্থানচ্যুত হয়নি - অপ্রত্যাশিত পার্শ্ব প্রতিক্রিয়া হিসাবে ঘটতে পারে।
t0rst

@ t0rst, দুঃখিত, একাধিক অ্যানিমেশন রয়েছে এবং অনুলিপি পেস্ট ব্যবহার করে, আমি একই অ্যানিমেশন ভেরিয়েবলে বিভিন্ন মান সেট করেছিলাম।
Iulian Onofrei

2

আমি উপরের সেরা উত্তরের উপর ভিত্তি করে বেশিরভাগ আপত্তিজনক উত্তর দেখতে পাচ্ছি 2.

শুরু করার জন্য এই সমস্ত কীটি একটি ব্যক্তিগত কাঠামোতে সংরক্ষণ করা ভাল হবে যাতে এটি নিরাপদ টাইপ হয় এবং ভবিষ্যতে এটি পরিবর্তন করা আপনাকে বিরক্তিকর বাগগুলি এনে দেয় না কারণ আপনি কোডের যে কোনও জায়গায় এটি পরিবর্তন করতে ভুলে গেছেন:

private struct AnimationKeys {
    static let animationType = "animationType"
    static let volumeControl = "volumeControl"
    static let throbUp = "throbUp"
}

আপনি দেখতে পাচ্ছেন যে আমি ভেরিয়েবল / অ্যানিমেশনগুলির নাম পরিবর্তন করেছি তাই এটি আরও স্পষ্ট। অ্যানিমেশন তৈরি হয়ে গেলে এখন এই কীগুলি সেট করুন।

volumeControlAnimation.setValue(AnimationKeys.volumeControl, forKey: AnimationKeys.animationType)

(...)

throbUpAnimation.setValue(AnimationKeys.throbUp, forKey: AnimationKeys.animationType)

তারপরে অ্যানিমেশনটি বন্ধ হয়ে গেলে অবশেষে প্রতিনিধিকে পরিচালনা করা

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
    if let value = anim.valueForKey(AnimationKeys.animationType) as? String {
        if value == AnimationKeys.volumeControl {
            //Do volumeControl handling
        } else if value == AnimationKeys.throbUp {
            //Do throbUp handling
        }
    }
}

0

আইএমএইচও-র অ্যাপল-এর ​​মূল-মানটি ব্যবহার করা হ'ল মার্জিত উপায়: এটি নির্দিষ্টভাবে বস্তুর সাথে অ্যাপ্লিকেশন নির্দিষ্ট ডেটা যুক্ত করার অনুমতি দেয়।

অন্যান্য খুব কম মার্জিত সম্ভাবনা হ'ল আপনার অ্যানিমেশন বস্তুর জন্য রেফারেন্সগুলি সঞ্চয় করা এবং সেগুলি সনাক্ত করার জন্য একটি পয়েন্টার তুলনা করা।


এটি কখনই কাজ করবে না - আপনি পয়েন্টার সমতুল্যতা করতে পারবেন না, কারণ অ্যাপল পয়েন্টারটি পরিবর্তন করে।
অ্যাডাম

0

আমার কাছে 2 সিবাসিক অ্যানিমেশন অবজেক্ট একই অ্যানিমেশন রয়েছে কিনা তা খতিয়ে দেখার জন্য আমি কীপ্যাথ ফাংশনটি ঠিক তেমনটি করতে ব্যবহার করি।

যদি ([অ্যানিমেশনএ কীপথ] == [অ্যানিমেশনবি কীপথ])

  • CabasicAnimation এর জন্য কীপথ সেট করার দরকার নেই কারণ এটি আর অ্যানিমেট করবে না

প্রশ্ন callbacks প্রতিনিধির নিকট হস্তান্তরের বর্ণনা করেন এবং keyPath CAAnimation উপর একটি পদ্ধতি নয়
ম্যাক্স ম্যাকলিয়ড

0

আমি ব্যবহার করতে চাই setValue:forKey: আমি যে অ্যানিমেট করছি তার একটি রেফারেন্স রাখতে আইডির ভিত্তিতে অ্যানিমেশনটি অনন্যভাবে সনাক্ত করার চেষ্টা করার চেয়ে এটি আরও নিরাপদ কারণ একই ধরণের অ্যানিমেশন বিভিন্ন স্তরে যুক্ত করা যেতে পারে।

এই দুটি সমতুল্য:

[UIView animateWithDuration: 0.35
                 animations: ^{
                     myLabel.alpha = 0;
                 } completion: ^(BOOL finished) {
                     [myLabel removeFromSuperview];
                 }];

এটার সাথে:

CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeOut.fromValue = @([myLabel.layer opacity]);
fadeOut.toValue = @(0.0);
fadeOut.duration = 0.35;
fadeOut.fillMode = kCAFillModeForwards;
[fadeOut setValue:myLabel forKey:@"item"]; // Keep a reference to myLabel
fadeOut.delegate = self;
[myLabel.layer addAnimation:fadeOut forKey:@"fadeOut"];
myLabel.layer.opacity = 0;

এবং প্রতিনিধি পদ্ধতিতে:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    id item = [anim valueForKey:@"item"];

    if ([item isKindOfClass:[UIView class]])
    {
        // Here you can identify the view by tag, class type 
        // or simply compare it with a member object

        [(UIView *)item removeFromSuperview];
    }
}

0

এক্সকোড 9 সুইফট 4.0

অ্যানিমেশনডিডস্টপ প্রতিনিধি পদ্ধতিতে ফিরে আসা অ্যানিমেশনটিতে আপনি যে অ্যানিমেশনটি যুক্ত করেছিলেন তাতে সম্পর্কিত করতে আপনি মূল মানগুলি ব্যবহার করতে পারেন।

সমস্ত সক্রিয় অ্যানিমেশন এবং সম্পর্কিত পরিপূর্ণতা থাকতে একটি অভিধান ঘোষণা করুন:

 var animationId: Int = 1
 var animating: [Int : () -> Void] = [:]

আপনি যখন আপনার অ্যানিমেশন যুক্ত করেন, এর জন্য একটি কী সেট করুন:

moveAndResizeAnimation.setValue(animationId, forKey: "CompletionId")
animating[animationId] = {
    print("completion of moveAndResize animation")
}
animationId += 1    

অ্যানিমেশনডিসটপ এ, যাদুটি ঘটে:

    let animObject = anim as NSObject
    if let keyValue = animObject.value(forKey: "CompletionId") as? Int {
        if let completion = animating.removeValue(forKey: keyValue) {
            completion()
        }
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.