diff --git a/Demo/SGTabs.xcodeproj/project.pbxproj b/Demo/SGTabs.xcodeproj/project.pbxproj index 6dbf0fc..6d56e31 100644 --- a/Demo/SGTabs.xcodeproj/project.pbxproj +++ b/Demo/SGTabs.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + F450946C15856EC800B7B1C6 /* cross.png in Resources */ = {isa = PBXBuildFile; fileRef = F450946B15856EC800B7B1C6 /* cross.png */; }; F470D27F1580EA5100ED3644 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F470D27E1580EA5100ED3644 /* UIKit.framework */; }; F470D2811580EA5100ED3644 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F470D2801580EA5100ED3644 /* Foundation.framework */; }; F470D2831580EA5100ED3644 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F470D2821580EA5100ED3644 /* CoreGraphics.framework */; }; @@ -22,6 +23,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + F450946B15856EC800B7B1C6 /* cross.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cross.png; sourceTree = ""; }; F470D27A1580EA5100ED3644 /* SGTabs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SGTabs.app; sourceTree = BUILT_PRODUCTS_DIR; }; F470D27E1580EA5100ED3644 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; F470D2801580EA5100ED3644 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -41,16 +43,17 @@ F470D2AB1580ECDB00ED3644 /* SGTabsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsView.m; sourceTree = ""; }; F470D2AD1580ECE700ED3644 /* SGTabView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabView.h; sourceTree = ""; }; F470D2AE1580ECE700ED3644 /* SGTabView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabView.m; sourceTree = ""; }; - F470D2B01580ED3000ED3644 /* SGToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; path = SGToolbar.h; sourceTree = ""; }; + F470D2B01580ED3000ED3644 /* SGToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGToolbar.h; sourceTree = ""; }; F470D2B11580ED3000ED3644 /* SGToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGToolbar.m; sourceTree = ""; }; F476BFBF15816C8E00BABEEB /* SGTabView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabView.h; sourceTree = ""; }; F476BFC015816C8E00BABEEB /* SGTabView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabView.m; sourceTree = ""; }; - F476BFC115816C8E00BABEEB /* SGToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; path = SGToolbar.h; sourceTree = ""; }; - F476BFC215816C8E00BABEEB /* SGToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; path = SGToolbar.m; sourceTree = ""; }; + F476BFC115816C8E00BABEEB /* SGToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGToolbar.h; sourceTree = ""; }; + F476BFC215816C8E00BABEEB /* SGToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGToolbar.m; sourceTree = ""; }; F476BFC315816C8E00BABEEB /* SGTabsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsView.h; sourceTree = ""; }; F476BFC415816C8E00BABEEB /* SGTabsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsView.m; sourceTree = ""; }; F476BFC515816C8E00BABEEB /* SGTabsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsViewController.h; sourceTree = ""; }; F476BFC615816C8E00BABEEB /* SGTabsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsViewController.m; sourceTree = ""; }; + F493636B158686E200FBD5F3 /* SGTabDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SGTabDefines.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -124,6 +127,7 @@ F470D2A61580EAD700ED3644 /* Source */ = { isa = PBXGroup; children = ( + F450946B15856EC800B7B1C6 /* cross.png */, F470D2A71580EAD700ED3644 /* SGTabsViewController.h */, F470D2A81580EAD700ED3644 /* SGTabsViewController.m */, F470D2AA1580ECDB00ED3644 /* SGTabsView.h */, @@ -132,6 +136,7 @@ F470D2AE1580ECE700ED3644 /* SGTabView.m */, F470D2B01580ED3000ED3644 /* SGToolbar.h */, F470D2B11580ED3000ED3644 /* SGToolbar.m */, + F493636B158686E200FBD5F3 /* SGTabDefines.h */, ); name = Source; path = ../Source; @@ -207,6 +212,7 @@ files = ( F470D2891580EA5100ED3644 /* InfoPlist.strings in Resources */, F470D2951580EA5100ED3644 /* SGViewController.xib in Resources */, + F450946C15856EC800B7B1C6 /* cross.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -303,6 +309,7 @@ GCC_PREFIX_HEADER = "SGTabs/SGTabs-Prefix.pch"; INFOPLIST_FILE = "SGTabs/SGTabs-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Debug; @@ -314,6 +321,7 @@ GCC_PREFIX_HEADER = "SGTabs/SGTabs-Prefix.pch"; INFOPLIST_FILE = "SGTabs/SGTabs-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/Demo/SGTabs/SGAppDelegate.h b/Demo/SGTabs/SGAppDelegate.h index 5d1a06b..addba77 100644 --- a/Demo/SGTabs/SGAppDelegate.h +++ b/Demo/SGTabs/SGAppDelegate.h @@ -25,7 +25,6 @@ @class SGTabsViewController; @interface SGAppDelegate : UIResponder { - NSTimer *timer; } @property (strong, nonatomic) UIWindow *window; diff --git a/Demo/SGTabs/SGAppDelegate.m b/Demo/SGTabs/SGAppDelegate.m index 1f500d6..7b7d8a1 100644 --- a/Demo/SGTabs/SGAppDelegate.m +++ b/Demo/SGTabs/SGAppDelegate.m @@ -34,32 +34,24 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. -// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { -// self.viewController = [[SGViewController alloc] initWithNibName:@"SGViewController_iPhone" bundle:nil]; -// } else { -// self.viewController = [[SGViewController alloc] initWithNibName:@"SGViewController_iPad" bundle:nil]; -// } self.tabController = [[SGTabsViewController alloc] initEditable:YES]; self.window.rootViewController = self.tabController; [self.window makeKeyAndVisible]; - [self openTab]; - timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(openTab) userInfo:nil repeats:YES]; + + [self performSelector:@selector(openTab) withObject:nil afterDelay:1]; return YES; } - (void)openTab { - if (4 > self.tabController.count) { // You can add up to tabController.maxCount Tabs - SGViewController *vc = [[SGViewController alloc] - initWithNibName:NSStringFromClass([SGViewController class]) - bundle:nil]; - vc.title = [NSString stringWithFormat:@"Tab %i content", self.tabController.count+1]; - [self.tabController addTab:vc]; - } else if (self.tabController.count == 4){ - [self.tabController setToolbarHidden:NO animated:YES]; - } + [self.tabController setToolbarHidden:NO animated:YES]; + SGViewController *vc = [[SGViewController alloc] + initWithNibName:NSStringFromClass([SGViewController class]) + bundle:nil]; + vc.title = [NSString stringWithFormat:@"Tab %i content", self.tabController.count+1]; + [self.tabController addTab:vc]; } @end diff --git a/Demo/SGTabs/SGViewController.m b/Demo/SGTabs/SGViewController.m index b48d9f9..925a83e 100644 --- a/Demo/SGTabs/SGViewController.m +++ b/Demo/SGTabs/SGViewController.m @@ -34,6 +34,16 @@ - (void)viewDidLoad [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.label.text = self.title; + + UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace + target:nil action:nil]; + UIBarButtonItem *trash = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash + target:self + action:@selector(remove:)]; + UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd + target:self + action:@selector(add:)]; + self.toolbarItems = [NSArray arrayWithObjects:space, trash, add, nil]; } - (void)viewDidUnload @@ -43,6 +53,14 @@ - (void)viewDidUnload // Release any retained subviews of the main view. } +- (void)viewWillDisappear:(BOOL)animated { + NSLog(@"viewWillDisappear"); +} + +- (void)viewDidDisappear:(BOOL)animated { + NSLog(@"ViewDidDisappear"); +} + - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { @@ -51,5 +69,21 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface return YES; } } + +- (IBAction)remove:(id)sender { + SGTabsViewController *tabs = (SGTabsViewController *) self.parentViewController; + [tabs removeViewController:self]; +} + +- (IBAction)add:(id)sender { + SGTabsViewController *tabs = (SGTabsViewController *) self.parentViewController; + + SGViewController *vc = [[SGViewController alloc] + initWithNibName:NSStringFromClass([SGViewController class]) + bundle:nil]; + vc.title = [NSString stringWithFormat:@"Tab %i content", tabs.count+1]; + [tabs addTab:vc]; + +} @end diff --git a/Demo/SGTabs/en.lproj/SGViewController.xib b/Demo/SGTabs/en.lproj/SGViewController.xib index 78cf45e..5c32c46 100644 --- a/Demo/SGTabs/en.lproj/SGViewController.xib +++ b/Demo/SGTabs/en.lproj/SGViewController.xib @@ -38,8 +38,10 @@ 274 - {{77, 83}, {167, 142}} + {{77, 159}, {167, 142}} + + _NS:9 NO YES @@ -54,6 +56,7 @@ 0 10 + 1 1 35 @@ -67,6 +70,8 @@ {{0, 20}, {320, 460}} + + 3 MQA @@ -143,7 +148,29 @@ 10 - + + + + SGViewController + UIViewController + + label + UILabel + + + label + + label + UILabel + + + + IBProjectSource + ./Classes/SGViewController.h + + + + 0 IBCocoaTouchFramework diff --git a/README.md b/README.md index a41f199..c1213c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,20 @@ # SGTabs -Tab component for iOS 5+. You can show your ViewControllers in tabs, it is possible to add and remove tabs on the fly +Tab component for iOS 5+. You can show your ViewControllers in tabs, it is possible to add and remove tabs on the fly. + +# Features +- Uses iOS 5 UIViewController Container API +- Add and remove tabs on the fly with animations +- User can remove tabs by pressing an X on a tab. TODO +- Dynamically show and hide a UIToolbar at the top +- Show the UIBarButtonItems in viewController.toolbarItems in the toolbar +- It should be possible to create Safari style apps + +# Screenshots + +![Multiple Tabs open][screen.png "Multiple Tabs open"] + +![Toolbar visible][screen_Toolbar.png "A Toolbar with one element visible"] diff --git a/Source/SGTabDefines.h b/Source/SGTabDefines.h new file mode 100644 index 0000000..c225b4a --- /dev/null +++ b/Source/SGTabDefines.h @@ -0,0 +1,41 @@ +// +// SGTabDefines.h +// SGTabs +// +// Created by simon on 11.06.12. +// +// +// Copyright (c) 2012 Simon Grätzer +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef SGTabs_SGTabConstants_h +#define SGTabs_SGTabConstants_h + +#define kAddTabDuration 0.4 +#define kRemoveTabDuration 0.4 + +#define kTabsToolbarHeigth 10.0 +#define kTabsToolbarHeigthFull 44.0 +#define kTabsHeigth 30.0 + +#define kCornerRadius 7.5 + +#define kShadowRadius 6.0 + +#define kTabColor [[UIColor alloc] initWithWhite:0.85 alpha:1] +#define kTabUnselectedColor [[UIColor alloc] initWithWhite:0.7 alpha:1] +//[[UIColor alloc] initWithWhite:0.6 alpha:1] + +#endif diff --git a/Source/SGTabView.h b/Source/SGTabView.h index c62fa97..202d9ac 100644 --- a/Source/SGTabView.h +++ b/Source/SGTabView.h @@ -23,14 +23,12 @@ #import -@interface SGTabView : UIView { - UIColor *topColor; - UIColor *bottomColor; -} +@interface SGTabView : UIView @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UIButton *closeButton; -@property (nonatomic, assign) BOOL editable; + +@property (nonatomic, strong) UIColor *tabColor; - (id)initWithFrame:(CGRect)frame title:(NSString *)title; diff --git a/Source/SGTabView.m b/Source/SGTabView.m index a038750..7f32ac7 100644 --- a/Source/SGTabView.m +++ b/Source/SGTabView.m @@ -21,14 +21,16 @@ // #import "SGTabView.h" +#import "SGTabDefines.h" + #import -#define kRadius 10.0 -#define kMargin 2*kRadius + @implementation SGTabView -@synthesize titleLabel, editable, closeButton; +@synthesize titleLabel, closeButton; +@synthesize tabColor; - (CGRect)tabRect { return CGRectMake(self.bounds.origin.x, @@ -55,12 +57,14 @@ - (id)initWithFrame:(CGRect)frame title:(NSString *)title self.titleLabel.shadowColor = [UIColor colorWithWhite:1 alpha:0.5]; self.titleLabel.shadowOffset = CGSizeMake(0, 0.5); [self addSubview:self.titleLabel]; - topColor = [[UIColor alloc] initWithWhite:0.9 alpha:1]; - bottomColor = [[UIColor alloc] initWithWhite:0.8 alpha:1]; - self.closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; -// [self.closeButton setImage:[UIImage imageNamed:@"button_close"] +// self.closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; +// [self.closeButton setTitle:@"Hello" forState:UIControlStateNormal]; +// [self.closeButton setImage:[UIImage imageNamed:@"cross.png"] // forState:UIControlStateNormal]; + [self addSubview:self.closeButton]; + + self.tabColor = kTabColor; } return self; } @@ -68,9 +72,9 @@ - (id)initWithFrame:(CGRect)frame title:(NSString *)title - (void)layoutSubviews { CGRect inner = [self tabRect]; self.titleLabel.frame = inner; - CGSize size = self.closeButton.frame.size; - self.closeButton.center = CGPointMake(inner.size.width - size.width, - inner.size.height/2); +// inner.origin.x -= 10; +// inner.size.width -=10; +// self.closeButton.frame = inner; } - (void)drawRect:(CGRect)rect { @@ -78,69 +82,39 @@ - (void)drawRect:(CGRect)rect { CGFloat tabLeft = tabRect.origin.x; CGFloat tabRight = tabRect.origin.x + tabRect.size.width; CGFloat tabTop = tabRect.origin.y; - CGFloat tabBottom = tabRect.origin.y + tabRect.size.height + 0.5; + CGFloat tabBottom = tabRect.origin.y + tabRect.size.height; - UIBezierPath *bPath = [UIBezierPath bezierPath]; + CGMutablePathRef path = CGPathCreateMutable(); - [bPath moveToPoint:CGPointMake(tabLeft, tabTop)]; + CGPathMoveToPoint(path, NULL, tabLeft, tabTop); // Top left - [bPath addArcWithCenter:CGPointMake(tabLeft, tabTop + kRadius) radius:kRadius startAngle:3*M_PI_2 endAngle:0 clockwise:YES]; + CGPathAddArc(path, NULL, tabLeft, tabTop + kCornerRadius, kCornerRadius, -M_PI_2, 0, NO); + CGPathAddLineToPoint(path, NULL, tabLeft + kCornerRadius, tabBottom - kCornerRadius); - [bPath addLineToPoint:CGPointMake(tabLeft + kRadius, tabBottom - kRadius)]; // Bottom left - [bPath addArcWithCenter:CGPointMake(tabLeft + 2*kRadius, tabBottom - kRadius) radius:kRadius startAngle:M_PI endAngle:M_PI_2 clockwise:NO]; + CGPathAddArc(path, NULL, tabLeft + 2*kCornerRadius, tabBottom - kCornerRadius, kCornerRadius, M_PI, M_PI_2, YES); + CGPathAddLineToPoint(path, NULL, tabRight - 2*kCornerRadius, tabBottom); - [bPath addLineToPoint:CGPointMake(tabRight - 2*kRadius, tabBottom)]; // Bottom rigth - [bPath addArcWithCenter:CGPointMake(tabRight - 2*kRadius, tabBottom - kRadius) radius:kRadius startAngle:M_PI_2 endAngle:0 clockwise:NO]; + CGPathAddArc(path, NULL, tabRight - 2*kCornerRadius, tabBottom - kCornerRadius, kCornerRadius, M_PI_2, 0, YES); + CGPathAddLineToPoint(path, NULL, tabRight - kCornerRadius, tabTop + kCornerRadius); - [bPath addLineToPoint:CGPointMake(tabRight - kRadius, tabTop + kRadius)]; // Top rigth - [bPath addArcWithCenter:CGPointMake(tabRight, tabTop + kRadius) radius:kRadius startAngle:M_PI endAngle:3*M_PI_2 clockwise:YES]; - - [bPath addLineToPoint:CGPointMake(tabRight, tabTop)]; - [bPath closePath]; - - CGPathRef path = [bPath CGPath]; - - CGContextRef context = UIGraphicsGetCurrentContext(); + CGPathAddArc(path, NULL, tabRight, tabTop + kCornerRadius, kCornerRadius, M_PI, -M_PI_2, NO); + CGPathAddLineToPoint(path, NULL, tabRight, tabTop); + CGPathCloseSubpath(path); + CGContextRef ctx = UIGraphicsGetCurrentContext(); // Fill with current tab color - CGColorRef startColor = [topColor CGColor]; - - CGContextSaveGState(context); - CGContextAddPath(context, path); - CGContextSetFillColorWithColor(context, startColor); - CGContextSetShadow(context, CGSizeMake(0, 5), 3.0); - CGContextFillPath(context); - CGContextRestoreGState(context); - - // Render the interior of the tab path using the gradient. - - // Configure a linear gradient which adds a simple white highlight on the top. - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGFloat locations[] = { 0.0, 0.5 }; - - - CGColorRef endColor = [bottomColor CGColor]; - - const void* colors[] = {startColor, endColor}; - - CFArrayRef colorArray = CFArrayCreate(NULL, colors, 2, &kCFTypeArrayCallBacks); - CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colorArray, locations); - CFRelease(colorArray); + CGColorRef startColor = [self.tabColor CGColor]; - CGPoint startPoint = CGPointMake(CGRectGetMidX(tabRect), tabRect.origin.y); - CGPoint endPoint = CGPointMake(CGRectGetMidX(tabRect), tabRect.origin.y + tabRect.size.height); + CGContextSaveGState(ctx); + CGContextAddPath(ctx, path); + CGContextSetFillColorWithColor(ctx, startColor); + CGContextSetShadow(ctx, CGSizeMake(0, -1), kShadowRadius); + CGContextFillPath(ctx); + CGContextRestoreGState(ctx); - CGContextSaveGState(context); - CGContextAddPath(context, path); - CGContextClip(context); - CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); - CGContextRestoreGState(context); - CGGradientRelease(gradient); - CGColorSpaceRelease(colorSpace); } @end diff --git a/Source/SGTabsView.m b/Source/SGTabsView.m index 7a582bf..e522789 100644 --- a/Source/SGTabsView.m +++ b/Source/SGTabsView.m @@ -23,6 +23,7 @@ #import "SGTabsView.h" #import "SGTabView.h" #import "SGTabsViewController.h" +#import "SGTabDefines.h" #define kMARGIN 2.5 @@ -37,7 +38,7 @@ - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { - self.backgroundColor = [UIColor clearColor]; + self.backgroundColor = [UIColor grayColor]; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin| UIViewAutoresizingFlexibleLeftMargin; self.autoresizesSubviews = YES; } @@ -51,13 +52,17 @@ - (NSMutableArray *)tabs { return _tabs; } +- (void)layoutSubviews{ + [self resizeTabs]; +} + #pragma mark - Tab operations - (void)addTab:(NSString *)title { CGFloat width = [self tabWidth:self.tabs.count+1]; CGRect frame = CGRectMake(self.bounds.size.width, 0, width, self.bounds.size.height - kMARGIN); SGTabView *newTab = [[SGTabView alloc] initWithFrame:frame title:title]; - newTab.editable = self.tabsController.editable; + newTab.closeButton.hidden = !self.tabsController.editing; UITapGestureRecognizer *tapG = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; @@ -83,8 +88,10 @@ - (void)addTab:(NSString *)title { if (i == self.tabs.count-1) { tab.alpha = 1.0; [self bringSubviewToFront:tab]; - } else - tab.alpha = 0.6; + } else { + tab.alpha = 0.7; + } + [tab setNeedsDisplay]; } } @@ -94,29 +101,20 @@ - (void)removeTab:(NSUInteger)index { [self.tabs removeObjectAtIndex:index]; [oldTab removeFromSuperview]; [self resizeTabs]; -// [UIView transitionWithView:self -// duration:0.3 -// options:UIViewAnimationOptionCurveEaseInOut -// animations:^{ -// [oldTab removeFromSuperview]; -// [self resizeTabs]; -// } -// completion:NULL]; } } - (void)setSelected:(NSUInteger)selected { - if (_selected != selected) { - _selected = selected; - for (int i = 0; i < self.tabs.count; i++) { - SGTabView *tab = [self.tabs objectAtIndex:i]; - if (i == selected) { - tab.alpha = 1.0; - [self bringSubviewToFront:tab]; - } else { - tab.alpha = 0.6; - } + _selected = selected; + for (int i = 0; i < self.tabs.count; i++) { + SGTabView *tab = [self.tabs objectAtIndex:i]; + if (i == selected) { + tab.alpha = 1.0; + [self bringSubviewToFront:tab]; + } else { + tab.alpha = 0.7; } + [tab setNeedsDisplay]; } } @@ -126,8 +124,8 @@ - (CGFloat)tabWidth:(NSUInteger)count { if (count > 0) width = (self.bounds.size.width - 2*kMARGIN)/count; else - width = 300.0; - return MIN(width, 300.0); + width = 360.0; + return MIN(width, 360.0); } diff --git a/Source/SGTabsViewController.m b/Source/SGTabsViewController.m index 15c1966..3e773ba 100644 --- a/Source/SGTabsViewController.m +++ b/Source/SGTabsViewController.m @@ -24,10 +24,8 @@ #import "SGToolbar.h" #import "SGTabsView.h" #import "SGTabView.h" +#import "SGTabDefines.h" -#define kTabsTopViewHeigth 10.0 -#define kTabsTopViewHeigthFull 44.0 -#define kTabsHeigth 30.0 @interface SGTabsViewController () @property (nonatomic, strong) UIView *headerView; @@ -67,7 +65,6 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - [self.tabsView resizeTabs]; CGRect head = self.headerView.frame; CGRect bounds = self.view.bounds; _contentFrame = CGRectMake(bounds.origin.x, @@ -82,14 +79,14 @@ - (void)loadView { CGRect bounds = self.view.bounds; - CGRect head = CGRectMake(bounds.origin.x, bounds.origin.y, bounds.size.width, kTabsTopViewHeigth + kTabsHeigth); + CGRect head = CGRectMake(bounds.origin.x, bounds.origin.y, bounds.size.width, kTabsToolbarHeigth + kTabsHeigth); self.headerView = [[UIView alloc] initWithFrame:head]; self.headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - CGRect frame = CGRectMake(head.origin.x, head.origin.y, head.size.width, kTabsTopViewHeigth); + CGRect frame = CGRectMake(head.origin.x, head.origin.y, head.size.width, kTabsToolbarHeigth); _toolbar = [[SGToolbar alloc] initWithFrame:frame]; - frame = CGRectMake(head.origin.x, kTabsTopViewHeigth, head.size.width, kTabsHeigth); + frame = CGRectMake(head.origin.x, kTabsToolbarHeigth, head.size.width, kTabsHeigth); _tabsView = [[SGTabsView alloc] initWithFrame:frame]; _tabsView.tabsController = self; @@ -118,9 +115,12 @@ - (void)addTab:(UIViewController *)viewController { [self addChildViewController:viewController]; viewController.view.frame = _contentFrame; + if (_toobarVisible) + [self.toolbar setItems:viewController.toolbarItems animated:YES]; + // Add tab selects automatically the new tab [UIView transitionWithView:self.view - duration:0.5 + duration:kAddTabDuration options:UIViewAnimationOptionAllowAnimatedContent animations:^{ [self.tabsView addTab:viewController.title]; @@ -150,14 +150,16 @@ - (void)showViewController:(UIViewController *)viewController index:(NSUInteger) if ([self.delegate respondsToSelector:@selector(willShowTab:)]) { [self.delegate willShowTab:viewController]; } - self.tabsView.selected = index; + + if (_toobarVisible) + [self.toolbar setItems:viewController.toolbarItems animated:YES]; [self transitionFromViewController:self.currentViewController toViewController:viewController duration:0 options:UIViewAnimationOptionAllowAnimatedContent animations:^{ - + self.tabsView.selected = index; viewController.view.frame = _contentFrame; } completion:^(BOOL finished) { @@ -180,40 +182,47 @@ - (void)removeViewController:(UIViewController *)viewController index:(NSUIntege [self.delegate willRemoveTab:viewController]; } - if (self.currentViewController == viewController) { - if (index < self.count - 1) - index++; - else if (index > 0) - index--; - else {// View controller is the last one - [viewController willMoveToParentViewController:nil]; - [viewController viewWillDisappear:NO]; - [viewController.view removeFromSuperview]; - [viewController viewDidDisappear:NO]; - [viewController removeFromParentViewController]; - _currentViewController = nil; - return; - } + [self.tabContents removeObjectAtIndex:index]; + if (self.tabContents.count == 0) {//View controller was the last one + [viewController willMoveToParentViewController:nil]; + _currentViewController = nil; + [UIView transitionWithView:self.tabsView + duration:kRemoveTabDuration + options:0 + animations:^{ + [viewController viewWillDisappear:NO]; + [viewController.view removeFromSuperview]; + [viewController viewDidDisappear:NO]; + [self.tabsView removeTab:index]; + [self.toolbar setItems:nil animated:NO]; + } + completion:^(BOOL finished){ + [viewController removeFromParentViewController]; + }]; + return; + } else if (index >= self.tabContents.count) { + index = self.tabContents.count-1; } UIViewController *to = [self.tabContents objectAtIndex:index]; - [self.tabContents removeObjectAtIndex:index]; [viewController willMoveToParentViewController:nil]; [UIView transitionWithView:self.view - duration:0.5 + duration:kRemoveTabDuration options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionCurveEaseInOut animations:^{ [self.tabsView removeTab:index]; - to.view.frame = _contentFrame; if (self.currentViewController == viewController) { [viewController viewWillDisappear:YES]; [viewController.view removeFromSuperview]; [viewController viewDidDisappear:YES]; + self.tabsView.selected = index; to.view.frame = _contentFrame; [self.view addSubview:to.view]; + if (_toobarVisible) + [self.toolbar setItems:to.toolbarItems animated:NO]; } } completion:^(BOOL finished){ @@ -234,21 +243,25 @@ - (void)removeIndex:(NSUInteger)index { } - (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated { - if (_toobarVisible != hidden) { + if (_toobarVisible != hidden) return; - } - _toobarVisible = !hidden; CGRect head = self.headerView.frame; CGRect toolbar = self.toolbar.frame; CGRect tabs = self.tabsView.frame; - CGFloat toolbarHeight = hidden ? kTabsTopViewHeigth : kTabsTopViewHeigthFull; + CGFloat toolbarHeight = hidden ? kTabsToolbarHeigth : kTabsToolbarHeigthFull; head.size.height = toolbarHeight+kTabsHeigth; toolbar.size.height = toolbarHeight; tabs.origin.y = toolbarHeight; _contentFrame.origin.y = head.size.height; + _toobarVisible = !hidden; + if (_toobarVisible) + [self.toolbar setItems:self.currentViewController.toolbarItems animated:animated]; + else + [self.toolbar setItems:nil animated:animated]; + [UIView animateWithDuration:animated ? 0.3 : 0 animations:^{ self.currentViewController.view.frame = _contentFrame; diff --git a/Source/SGToolbar.m b/Source/SGToolbar.m index 08b45d3..895132a 100644 --- a/Source/SGToolbar.m +++ b/Source/SGToolbar.m @@ -21,6 +21,7 @@ // #import "SGToolbar.h" +#import "SGTabDefines.h" @implementation SGToolbar @@ -36,23 +37,12 @@ - (id)initWithFrame:(CGRect)frame - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); - - CGFloat shadowRadius = 3.0; - - // We don't want to see the shadow anywhere but above the top edge. - // But the shadow only looks good when we _fill_ a path so we just - // use a rect whose left/right/bottom aren't visible. - - CGFloat bigValue = 1e6; - - CGRect r = CGRectMake(-bigValue, shadowRadius - 0.5, - self.frame.size.width + bigValue, bigValue); - - CGContextSaveGState(context); - CGContextSetShadow(context, CGSizeZero, shadowRadius); - CGContextSetFillColorWithColor(context, [[UIColor alloc] initWithWhite:0.9 alpha:1].CGColor); - CGContextFillRect(context, r); - CGContextRestoreGState(context); + + //CGContextSaveGState(context); + //CGContextSetShadow(context, CGSizeZero, kShadowRadius); + CGContextSetFillColorWithColor(context, [kTabColor CGColor]); + CGContextFillRect(context, self.bounds); + //CGContextRestoreGState(context); } @end diff --git a/Source/cross.png b/Source/cross.png new file mode 100644 index 0000000..a912052 Binary files /dev/null and b/Source/cross.png differ diff --git a/screen.png b/screen.png new file mode 100644 index 0000000..288d7ae Binary files /dev/null and b/screen.png differ diff --git a/screen_Toolbar.png b/screen_Toolbar.png new file mode 100644 index 0000000..ba98e91 Binary files /dev/null and b/screen_Toolbar.png differ