我在Storyboard
中收到UITabBarController
。現在,它已得到5 UITabBarItems
。當我在其他UITabBarItem
中時,我想更新其他UITabBarItem(我的「下載」)上的徽章,就像iTunes
應用在購買歌曲或專輯時使用此「跳躍式」動畫一樣。這可能嗎?如果是,如何?iOS:UITabbar中的iTunes-like徽章
謝謝。
我在Storyboard
中收到UITabBarController
。現在,它已得到5 UITabBarItems
。當我在其他UITabBarItem
中時,我想更新其他UITabBarItem(我的「下載」)上的徽章,就像iTunes
應用在購買歌曲或專輯時使用此「跳躍式」動畫一樣。這可能嗎?如果是,如何?iOS:UITabbar中的iTunes-like徽章
謝謝。
是...
有很多像我稱之爲動畫「發送到下載」類型的動畫。我會用一個例子回答這個問題。
警告:這個例子打破了MVC
的範例比我想要的,但它足夠長。
我將使用一個簡單的故事板這樣的(事實上,正是這個):
我會通過描述 「第一視圖控制器 - 第一個」 啓動:
視圖中的那些許多按鈕都連接到列出的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框架添加到您的應用程序。
謝謝,我現在不在家,但以後我會把這個輸出!非常感謝(我認爲這是很多工作,對吧?)! – user1710004