2012-09-29 87 views
3

我有一個基於動畫的應用程序。經過幾個小時的嘗試和搜索最有效的動畫處理器(這將有低延遲和最佳內存管理),我發現了驚人的PNGAnimator(http://www.modejong.com/iPhone/)。有趣的是,我實際上使用JPEG(由於大小),但這不是問題。將UIViewController代碼轉換爲UIView

問題是該類本身是UIViewController的一個子類,當我將它添加到我的rootViewController中時,新的視圖控制器會重疊它 - 因此所有界面元素(按鈕...)都隱藏在它下面。

這就是爲什麼我想以某種方式將代碼轉換爲UIView的子類。 (所以我可以添加按鈕)我試着自己轉換代碼,但是應用程序會在動畫調用中崩潰。你能告訴我,我應該在代碼中更改什麼,以便它可以充當UIView?

例如,我試圖將.h文件更改爲UIView,然後在.m文件中,將引用self.view更改爲self。然後在我的根視圖控制器添加它作爲一個子視圖,但不顯示和崩潰。

這裏是.h文件:

// 
// ImageAnimatorViewController.h 
// PNGAnimatorDemo 
// 
// Created by Moses DeJong on 2/5/09. 
// 

#import <UIKit/UIKit.h> 

#define ImageAnimator15FPS (1.0/15) 
#define ImageAnimator12FPS (1.0/12) 
#define ImageAnimator25FPS (1.0/24) 
#define ImageAnimator18FPS (1.0/18) 

#define ImageAnimatorDidStartNotification @"ImageAnimatorDidStartNotification" 
#define ImageAnimatorDidStopNotification @"ImageAnimatorDidStopNotification" 

@class AVAudioPlayer; 

@interface ImageAnimatorViewController : UIViewController { 

@public 

    NSArray *animationURLs; 

    NSTimeInterval animationFrameDuration; 

    NSInteger animationNumFrames; 

    NSInteger animationRepeatCount; 

    UIImageOrientation animationOrientation; 

    NSURL *animationAudioURL; 

    AVAudioPlayer *avAudioPlayer; 

@private 

    UIImageView *imageView; 

    NSArray *animationData; 

    NSTimer *animationTimer; 

    NSInteger animationStep; 

    NSTimeInterval animationDuration; 

    NSTimeInterval lastReportedTime; 
} 

// public properties 

@property (nonatomic, copy) NSArray *animationURLs; 
@property (nonatomic, assign) NSTimeInterval animationFrameDuration; 
@property (nonatomic, readonly) NSInteger animationNumFrames; 
@property (nonatomic, assign) NSInteger animationRepeatCount; 
@property (nonatomic, assign) UIImageOrientation animationOrientation; 
@property (nonatomic, retain) NSURL *animationAudioURL; 
@property (nonatomic, retain) AVAudioPlayer *avAudioPlayer; 
@property (nonatomic, assign) CGRect viewCGRect; 

// private properties 

@property (nonatomic, retain) UIImageView *imageView; 
@property (nonatomic, copy) NSArray *animationData; 
@property (nonatomic, retain) NSTimer *animationTimer; 
@property (nonatomic, assign) NSInteger animationStep; 
@property (nonatomic, assign) NSTimeInterval animationDuration; 

+ (ImageAnimatorViewController*) imageAnimatorViewController; 

- (void) startAnimating; 
- (void) stopAnimating; 
- (BOOL) isAnimating; 

- (void) animationShowFrame: (NSInteger) frame; 

+ (NSArray*) arrayWithNumberedNames:(NSString*)filenamePrefix 
         rangeStart:(NSInteger)rangeStart 
          rangeEnd:(NSInteger)rangeEnd 
         suffixFormat:(NSString*)suffixFormat; 

+ (NSArray*) arrayWithResourcePrefixedURLs:(NSArray*)inNumberedNames; 

@end 

這裏.m文件:

// 
// ImageAnimatorViewController.m 
// PNGAnimatorDemo 
// 
// Created by Moses DeJong on 2/5/09. 
// 

#import "ImageAnimatorViewController.h" 

#import <QuartzCore/QuartzCore.h> 

#import <AVFoundation/AVAudioPlayer.h> 

@implementation ImageAnimatorViewController 

@synthesize animationURLs, animationFrameDuration, animationNumFrames, animationRepeatCount, 
imageView, animationData, animationTimer, animationStep, animationDuration, animationOrientation, viewCGRect; 
@synthesize animationAudioURL, avAudioPlayer; 

- (void)dealloc { 
    // This object can't be deallocated while animating, this could 
    // only happen if user code incorrectly dropped the last ref. 

    NSAssert([self isAnimating] == FALSE, @"dealloc while still animating"); 

    self.animationURLs = nil; 
    self.imageView = nil; 
    self.animationData = nil; 
    self.animationTimer = nil; 

    [super dealloc]; 
} 

+ (ImageAnimatorViewController*) imageAnimatorViewController 
{ 
    return [[[ImageAnimatorViewController alloc] init] autorelease]; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    // Return YES for supported orientations 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 

// Implement loadView to create a view hierarchy programmatically, without using a nib. 

- (void)loadView { 
    UIView *myView = [[UIView alloc] initWithFrame:viewCGRect]; 
    [myView autorelease]; 
    self.view = myView; 
    /*UIView *myView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; 
    [myView autorelease]; 
    self.view = myView; 

    // FIXME: Additional Supported Orientations 

    if (animationOrientation == UIImageOrientationUp) { 
     // No-op 
    } else if (animationOrientation == UIImageOrientationLeft) { 
     // 90 deg CCW 
     //[self rotateToLandscape]; 
    } else if (animationOrientation == UIImageOrientationRight) { 
     // 90 deg CW 
     //[self rotateToLandscapeRight]; 
    } else { 
     NSAssert(FALSE,@"Unsupported animationOrientation"); 
    } 
*/ 
    // Foreground animation images 

    UIImageView *myImageView = [[UIImageView alloc] initWithFrame:self.view.frame]; 
    [myImageView autorelease]; 
    self.imageView = myImageView; 

    // Animation data should have already been loaded into memory as a result of 
    // setting the animationURLs property 

    NSAssert(animationURLs, @"animationURLs was not defined"); 
    NSAssert([animationURLs count] > 1, @"animationURLs must include at least 2 urls"); 
    NSAssert(animationFrameDuration, @"animationFrameDuration was not defined"); 

    // Load animationData by reading from animationURLs 

    NSMutableDictionary *dataDict = [NSMutableDictionary dictionaryWithCapacity:[animationURLs count]]; 

    NSMutableArray *muArray = [NSMutableArray arrayWithCapacity:[animationURLs count]]; 
    for (NSURL* aURL in animationURLs) { 
     NSString *urlKey = aURL.path; 
     NSData *dataForKey = [dataDict objectForKey:urlKey]; 

     if (dataForKey == nil) { 
      dataForKey = [NSData dataWithContentsOfURL:aURL]; 
      NSAssert(dataForKey, @"dataForKey"); 

      [dataDict setObject:dataForKey forKey:urlKey]; 
     } 

     [muArray addObject:dataForKey]; 
    } 
    self.animationData = [NSArray arrayWithArray:muArray]; 

    int numFrames = [animationURLs count]; 
    float duration = animationFrameDuration * numFrames; 

    self->animationNumFrames = numFrames; 
    self.animationDuration = duration; 

    [self.view addSubview:imageView]; 

    // Display first frame of image animation 

    self.animationStep = 0; 

    [self animationShowFrame: animationStep]; 

    self.animationStep = animationStep + 1; 

    if (animationAudioURL != nil) { 
     AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:animationAudioURL 
                     error:nil]; 
    [avPlayer autorelease]; 
     NSAssert(avPlayer, @"AVAudioPlayer could not be allocated"); 
     self.avAudioPlayer = avPlayer; 

     [avAudioPlayer prepareToPlay];  
    } 
} 

// Create an array of file/resource names with the given filename prefix, 
// the file names will have an integer appended in the range indicated 
// by the rangeStart and rangeEnd arguments. The suffixFormat argument 
// is a format string like "%02i.png", it must format an integer value 
// into a string that is appended to the file/resource string. 
// 
// For example: [createNumberedNames:@"Image" rangeStart:1 rangeEnd:3 rangeFormat:@"%02i.png"] 
// 
// returns: {"Image01.png", "Image02.png", "Image03.png"} 

+ (NSArray*) arrayWithNumberedNames:(NSString*)filenamePrefix 
           rangeStart:(NSInteger)rangeStart 
           rangeEnd:(NSInteger)rangeEnd 
          suffixFormat:(NSString*)suffixFormat 
{ 
    NSMutableArray *numberedNames = [[NSMutableArray alloc] initWithCapacity:40]; 

    for (int i = rangeStart; i <= rangeEnd; i++) { 
     NSString *suffix = [NSString stringWithFormat:suffixFormat, i]; 
     NSString *filename = [NSString stringWithFormat:@"%@%@", filenamePrefix, suffix]; 

     [numberedNames addObject:filename]; 
    } 

    NSArray *newArray = [NSArray arrayWithArray:numberedNames]; 
    [numberedNames release]; 
    return newArray; 
} 

// Given an array of resource names (as returned by arrayWithNumberedNames) 
// create a new array that contains these resource names prefixed as 
// resource paths and wrapped in a NSURL object. 

+ (NSArray*) arrayWithResourcePrefixedURLs:(NSArray*)inNumberedNames 
{ 
    NSMutableArray *URLs = [[NSMutableArray alloc] initWithCapacity:[inNumberedNames count]]; 
    NSBundle* appBundle = [NSBundle mainBundle]; 

    for (NSString* path in inNumberedNames) { 
     NSString* resPath = [appBundle pathForResource:path ofType:nil];  
     NSURL* aURL = [NSURL fileURLWithPath:resPath]; 

     [URLs addObject:aURL]; 
    } 

    NSArray *newArray = [NSArray arrayWithArray:URLs]; 
    [URLs release]; 
    return newArray; 
} 


// Invoke this method to start the animation 

- (void) startAnimating 
{ 
    self.animationTimer = [NSTimer timerWithTimeInterval: animationFrameDuration 
              target: self 
              selector: @selector(animationTimerCallback:) 
              userInfo: NULL 
              repeats: TRUE]; 

    [[NSRunLoop currentRunLoop] addTimer: animationTimer forMode: NSDefaultRunLoopMode]; 

    animationStep = 0; 

    if (avAudioPlayer != nil) 
     [avAudioPlayer play]; 

    // Send notification to object(s) that regestered interest in a start action 

    [[NSNotificationCenter defaultCenter] 
    postNotificationName:ImageAnimatorDidStartNotification 
    object:self]; 
} 

// Invoke this method to stop the animation, note that this method must not 
// invoke other methods and it must cancel any pending callbacks since 
// it could be invoked in a low-memory situation or when the object 
// is being deallocated. Invoking this method will not generate a 
// animation stopped notification, that callback is only invoked when 
// the animation reaches the end normally. 

- (void) stopAnimating 
{ 
    if (![self isAnimating]) 
     return; 

    [animationTimer invalidate]; 
    self.animationTimer = nil; 

    animationStep = animationNumFrames - 1; 
    [self animationShowFrame: animationStep]; 

    if (avAudioPlayer != nil) { 
     [avAudioPlayer stop]; 
     avAudioPlayer.currentTime = 0.0; 
     self->lastReportedTime = 0.0; 
    } 

    // Send notification to object(s) that regestered interest in a stop action 

    [[NSNotificationCenter defaultCenter] 
    postNotificationName:ImageAnimatorDidStopNotification 
    object:self]; 
} 

- (BOOL) isAnimating 
{ 
    return (animationTimer != nil); 
} 

// Invoked at framerate interval to implement the animation 

- (void) animationTimerCallback: (NSTimer *)timer { 
    if (![self isAnimating]) 
     return; 

    NSTimeInterval currentTime; 
    NSUInteger frameNow; 

    if (avAudioPlayer == nil) { 
     self.animationStep += 1; 

//  currentTime = animationStep * animationFrameDuration; 
     frameNow = animationStep; 
    } else { 
     currentTime = avAudioPlayer.currentTime; 
     frameNow = (NSInteger) (currentTime/animationFrameDuration); 
    } 

    // Limit the range of frameNow to [0, SIZE-1] 
    if (frameNow == 0) { 
     frameNow = 0; 
    } else if (frameNow >= animationNumFrames) { 
     frameNow = animationNumFrames - 1; 
    } 

    [self animationShowFrame: frameNow]; 
// animationStep = frameNow + 1; 

    if (animationStep >= animationNumFrames) { 
     [self stopAnimating]; 

     // Continue to loop animation until loop counter reaches 0 

     if (animationRepeatCount > 0) { 
      self.animationRepeatCount = animationRepeatCount - 1; 
      [self startAnimating]; 
     } 
    } 
} 

// Display the given animation frame, in the range [1 to N] 
// where N is the largest frame number. 

- (void) animationShowFrame: (NSInteger) frame { 
    if ((frame >= animationNumFrames) || (frame < 0)) 
     return; 

    NSData *data = [animationData objectAtIndex:frame]; 
    UIImage *img = [UIImage imageWithData:data]; 
    imageView.image = img; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    self.animationRepeatCount = 0; 

    [self stopAnimating]; 
} 

@end 

非常感謝您提出的任何建議!

回答

2

不知道爲什麼你被downvoted。我認爲你的問題是,UIViewController子類的loadView函數實現,並依賴它來構建用戶界面。在視圖控制器的情況下,如果未從.xib加載視圖,則會自動調用此函數以構建視圖。創建對象後,您可以嘗試手動調用此功能,它應該做幾乎相同的事情。

請記住,shouldAutorotateToInterfaceOrientation 功能也是UIViewController功能,決不會叫上UIView

+0

謝謝,不知道的downvote了。好的,我會嘗試手動調用它。 –

+0

因此,我嘗試手動調用它,並在應用程序崩潰斷言失敗在這一行 - \t NSAssert(animationURLs,@「animationURLs was not defined」); 。我該怎麼辦? –

+0

這是一個非常明顯的錯誤。它取決於某些元素,而且你沒有定義這些元素。你需要設置'animationURLS'和'animationFrameDuration'。 – Dima