2012-11-25 92 views
1

我在Storyboard中收到UITabBarController。現在,它已得到5 UITabBarItems。當我在其他UITabBarItem中時,我想更新其他UITabBarItem(我的「下載」)上的徽章,就像iTunes應用在購買歌曲或專輯時使用此「跳躍式」動畫一樣。這可能嗎?如果是,如何?iOS:UITabbar中的iTunes-like徽章

謝謝。

回答

1

是...

有很多像我稱之爲動畫「發送到下載」類型的動畫。我會用一個例子回答這個問題。

警告:這個例子打破了MVC的範例比我想要的,但它足夠長。

我將使用一個簡單的故事板這樣的(事實上,正是這個):

Storyboard showing a tabBarController with two view controllers. A first view controller, and a download view controller.

我會通過描述 「第一視圖控制器 - 第一個」 啓動:

視圖中的那些許多按鈕都連接到列出的IBAction方法。這就是關於該視圖控制器所需的所有描述。下面是它的.m文件:(截斷)

//#import "First_View_Controller.h" 
@interface First_View_Controller() 
@property (weak, nonatomic) DownloadViewController *downloadViewController; 
@end 

@implementation First_View_Controller 
@synthesize downloadViewController = _downloadViewController; 
-(DownloadViewController *)downloadViewController{ 
    if (!_downloadViewController){ 
     // Code to find instance of DownloadViewController in the tabBarController's view controllers. 
     for (UIViewController *vc in self.tabBarController.viewControllers) { 
      if ([vc isKindOfClass:[DownloadViewController class]]){ 
       _downloadViewController = (DownloadViewController *)vc; 
       break; 
      } 
     } 
    } 
    return _downloadViewController; 
} 
-(IBAction)buttonPush:(UIButton *)button{ 
    [self.downloadViewController addADownload:nil withViewToAnimate:button]; 
} 
// Other typical VC crap... 
@end 

IBAction是相當不言自明。它通過查看tabBarController的視圖控制器獲取對DownloadViewController實例的引用,並將視圖傳遞給該實例的動畫。

現在爲DownloadViewController.m。這是很多代碼。我已評論它,試圖說清楚:

#import "DownloadViewController.h" 
#import <QuartzCore/QuartzCore.h> 
// A Category on UITabBar to grab the view of a tab by index. 
@implementation UITabBar (WhyIsntThisBuiltIn) 
-(UIView *)nj_ViewOfTabNumber:(NSUInteger)number{ 
    if (number == NSNotFound) return nil; 
    // Fairly standard method for getting tabs, getting the UIControl objects from the 'subviews' array. 
    // I pulled the next few lines from an SO question. 
    NSMutableArray *tabs = [[NSMutableArray alloc] init]; 
    [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){ 
     if ([(NSObject *)obj isKindOfClass:UIControl.class]){ 
      [tabs addObject:obj]; 
     } 
    }]; 
    // The code above gets the tabs' views, but they may not be in the correct order. 
    // This sort is required if a view controller has been replaced,... 
    // Since, in that case, the order in which the tabs' views appear in the 'subviews' array will not be the left-to-right order. 
    [tabs sortUsingComparator:^NSComparisonResult(UIView *obj1, UIView *obj2){ 
     CGFloat v1 = obj1.center.x; 
     CGFloat v2 = obj2.center.x; 
     if (v1<v2) return NSOrderedAscending; 
     if (v1>v2) return NSOrderedDescending; 
     return NSOrderedSame; 
    }]; 
    // This if is required for the case where the view controller is in the "more" tab. 
    if (number >= tabs.count) number = tabs.count-1; 
    return [tabs objectAtIndex:number]; 
} 
@end 
// A Category on UITabBarController to get the view of a tab that represents a certain view controller. 
@implementation UITabBarController (WhyIsntThisBuiltIn) 
-(UIView *)nj_viewOfTabForViewController:(UIViewController *)viewController{ 
    // Find index of the passed in viewController. 
    NSUInteger indexOfViewController = [self.viewControllers indexOfObject:viewController]; 
    if (indexOfViewController == NSNotFound) return nil; 
    // Return the view of the tab representing the passed in viewController. 
    return [self.tabBar nj_ViewOfTabNumber:indexOfViewController]; 
} 
@end 

// Insert required warning about using #defines here. 
#define MY_ANIMATION_DURATION 0.8 
@implementation DownloadViewController{ 
    NSUInteger _numberOfDownloads; 
} 
-(void)updateBadgeValue{ 
    self.tabBarItem.badgeValue = [NSString stringWithFormat:@"%i",_numberOfDownloads]; 
} 
// This method creates a "snapshot" of the animation view and animates it to the "downloads" tab. 
// Removal of the original animationView must, if desired, be done manually by the caller. 
-(void)addADownload:(id)someDownload withViewToAnimate:(UIView *)animationView{ 
    // update model... 
    _numberOfDownloads++; 

    // Animate if required 
    if (animationView){ 

     // Create a `UIImageView` of the "animationView" name it `dummyImageView` 
     UIGraphicsBeginImageContextWithOptions(animationView.frame.size, NO, [[UIScreen mainScreen] scale]); 
     [animationView.layer renderInContext:UIGraphicsGetCurrentContext()]; 
     UIImage *dummyImage = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 
     UIImageView *dummyImageView = [[UIImageView alloc] initWithImage:dummyImage]; 
     dummyImageView.frame = animationView.frame; 

     // Determine UIView of tab using non-private API. 
     UITabBarController *tabBarController = self.tabBarController; 
     UIView *downloadsTab = [tabBarController nj_viewOfTabForViewController:self]; 

     // Determine animation points in tabBarController's view's coordinates. 
     CGPoint animationStartPoint = [tabBarController.view convertPoint:dummyImageView.center fromView:dummyImageView.superview]; 
     CGPoint animationEndPoint = [tabBarController.view convertPoint:downloadsTab.center fromView:downloadsTab.superview]; 
     CGFloat totalXTravel = animationEndPoint.x - animationStartPoint.x; 
     // This is an arbitrary equation to create a control point, this is by no means canonical. 
     CGPoint controlPoint = CGPointMake(animationEndPoint.x, animationStartPoint.y - fabs(totalXTravel/1.2)); 

     // Create the animation path. 
     UIBezierPath *path = [[UIBezierPath alloc] init]; 
     [path moveToPoint:animationStartPoint]; 
     [path addQuadCurveToPoint:animationEndPoint controlPoint:controlPoint]; 

     // Create the CAAnimation. 
     CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; 
     moveAnimation.duration = MY_ANIMATION_DURATION; 
     moveAnimation.path = path.CGPath; 
     moveAnimation.removedOnCompletion = NO; 
     moveAnimation.fillMode = kCAFillModeBoth; 

     [tabBarController.view addSubview:dummyImageView]; 
     dummyImageView.center = animationStartPoint; 

     // Animate the move. 
     [dummyImageView.layer addAnimation:moveAnimation forKey:@""]; 

     // Use the block based API to add size reduction and handle completion. 
     [UIView animateWithDuration:MY_ANIMATION_DURATION 
         animations:^{ 
          dummyImageView.transform = CGAffineTransformMakeScale(0.3, 0.3); 
         } 
         completion:^(BOOL b){ 
          // Animate BIG FINISH! nah, just... 
          [dummyImageView removeFromSuperview]; 
          [self updateBadgeValue]; 
         }]; 
    } 
} 
// Other typical VC crap... 
@end 

就是這樣。運行時,此代碼會從左上角的按鈕產生相當強的跳轉,但右側的按鈕,尤其是右下角的按鈕,會被排序。隨着動畫結束,下載選項卡上的徽章數量將增加。當您在iTunes上購買內容時,蘋果使用的效果相當不錯。

記得將Quartz框架添加到您的應用程序。

+0

謝謝,我現在不在家,但以後我會把這個輸出!非常感謝(我認爲這是很多工作,對吧?)! – user1710004