diff --git a/.gitignore b/.gitignore index edc082c..d48df52 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ build/* xcuserdata profile *.moved-aside + +Demo/.DS_Store + +.DS_Store diff --git a/Demo/SGTabs.xcodeproj/project.pbxproj b/Demo/SGTabs.xcodeproj/project.pbxproj index 4fc30e1..40f0460 100644 --- a/Demo/SGTabs.xcodeproj/project.pbxproj +++ b/Demo/SGTabs.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ F470D28F1580EA5100ED3644 /* SGAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D28E1580EA5100ED3644 /* SGAppDelegate.m */; }; F470D2921580EA5100ED3644 /* SGViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2911580EA5100ED3644 /* SGViewController.m */; }; F470D2951580EA5100ED3644 /* SGViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = F470D2931580EA5100ED3644 /* SGViewController_iPhone.xib */; }; - F470D2981580EA5100ED3644 /* SGViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = F470D2961580EA5100ED3644 /* SGViewController_iPad.xib */; }; F470D2A91580EAD700ED3644 /* SGTabsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2A81580EAD700ED3644 /* SGTabsViewController.m */; }; F470D2AC1580ECDB00ED3644 /* SGTabsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2AB1580ECDB00ED3644 /* SGTabsView.m */; }; F470D2AF1580ECE700ED3644 /* SGTabView.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2AE1580ECE700ED3644 /* SGTabView.m */; }; @@ -36,7 +35,6 @@ F470D2901580EA5100ED3644 /* SGViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SGViewController.h; sourceTree = ""; }; F470D2911580EA5100ED3644 /* SGViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SGViewController.m; sourceTree = ""; }; F470D2941580EA5100ED3644 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/SGViewController_iPhone.xib; sourceTree = ""; }; - F470D2971580EA5100ED3644 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/SGViewController_iPad.xib; sourceTree = ""; }; F470D2A71580EAD700ED3644 /* SGTabsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsViewController.h; sourceTree = ""; }; F470D2A81580EAD700ED3644 /* SGTabsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsViewController.m; sourceTree = ""; }; F470D2AA1580ECDB00ED3644 /* SGTabsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsView.h; sourceTree = ""; }; @@ -45,6 +43,14 @@ F470D2AE1580ECE700ED3644 /* SGTabView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabView.m; sourceTree = ""; }; F470D2B01580ED3000ED3644 /* SGTabsTopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsTopView.h; sourceTree = ""; }; F470D2B11580ED3000ED3644 /* SGTabsTopView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsTopView.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 /* SGTabsTopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SGTabsTopView.h; sourceTree = ""; }; + F476BFC215816C8E00BABEEB /* SGTabsTopView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SGTabsTopView.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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,7 +103,7 @@ F470D2901580EA5100ED3644 /* SGViewController.h */, F470D2911580EA5100ED3644 /* SGViewController.m */, F470D2931580EA5100ED3644 /* SGViewController_iPhone.xib */, - F470D2961580EA5100ED3644 /* SGViewController_iPad.xib */, + F476BFBE15816C8E00BABEEB /* Source */, F470D2851580EA5100ED3644 /* Supporting Files */, ); name = Demo; @@ -131,6 +137,22 @@ path = ../Source; sourceTree = ""; }; + F476BFBE15816C8E00BABEEB /* Source */ = { + isa = PBXGroup; + children = ( + F476BFBF15816C8E00BABEEB /* SGTabView.h */, + F476BFC015816C8E00BABEEB /* SGTabView.m */, + F476BFC115816C8E00BABEEB /* SGTabsTopView.h */, + F476BFC215816C8E00BABEEB /* SGTabsTopView.m */, + F476BFC315816C8E00BABEEB /* SGTabsView.h */, + F476BFC415816C8E00BABEEB /* SGTabsView.m */, + F476BFC515816C8E00BABEEB /* SGTabsViewController.h */, + F476BFC615816C8E00BABEEB /* SGTabsViewController.m */, + ); + name = Source; + path = ../../Source; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -185,7 +207,6 @@ files = ( F470D2891580EA5100ED3644 /* InfoPlist.strings in Resources */, F470D2951580EA5100ED3644 /* SGViewController_iPhone.xib in Resources */, - F470D2981580EA5100ED3644 /* SGViewController_iPad.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -225,14 +246,6 @@ name = SGViewController_iPhone.xib; sourceTree = ""; }; - F470D2961580EA5100ED3644 /* SGViewController_iPad.xib */ = { - isa = PBXVariantGroup; - children = ( - F470D2971580EA5100ED3644 /* en */, - ); - name = SGViewController_iPad.xib; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/Demo/SGTabs/SGAppDelegate.h b/Demo/SGTabs/SGAppDelegate.h index a67c2b6..2793508 100644 --- a/Demo/SGTabs/SGAppDelegate.h +++ b/Demo/SGTabs/SGAppDelegate.h @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import diff --git a/Demo/SGTabs/SGAppDelegate.m b/Demo/SGTabs/SGAppDelegate.m index b09aa34..795e04d 100644 --- a/Demo/SGTabs/SGAppDelegate.m +++ b/Demo/SGTabs/SGAppDelegate.m @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGAppDelegate.h" @@ -30,7 +44,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self.window makeKeyAndVisible]; [self.viewController addBlankTab:@"Hello World"]; - timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(openTab) userInfo:nil repeats:YES]; + timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(openTab) userInfo:nil repeats:YES]; return YES; } diff --git a/Demo/SGTabs/SGViewController.h b/Demo/SGTabs/SGViewController.h index 95b621c..3745214 100644 --- a/Demo/SGTabs/SGViewController.h +++ b/Demo/SGTabs/SGViewController.h @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import diff --git a/Demo/SGTabs/SGViewController.m b/Demo/SGTabs/SGViewController.m index b84beba..a067321 100644 --- a/Demo/SGTabs/SGViewController.m +++ b/Demo/SGTabs/SGViewController.m @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGViewController.h" diff --git a/Demo/SGTabs/en.lproj/SGViewController_iPad.xib b/Demo/SGTabs/en.lproj/SGViewController_iPad.xib deleted file mode 100644 index 426b3b9..0000000 --- a/Demo/SGTabs/en.lproj/SGViewController_iPad.xib +++ /dev/null @@ -1,120 +0,0 @@ - - - - 1280 - 11C25 - 1919 - 1138.11 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 916 - - - IBProxyObject - IBUIView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - {{0, 20}, {768, 1004}} - - - - 3 - MQA - - 2 - - - - 2 - - IBIPadFramework - - - - - - - view - - - - 3 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - SGViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 3 - - - - - SGViewController - UIViewController - - IBProjectSource - ./Classes/SGViewController.h - - - - - 0 - IBIPadFramework - YES - 3 - 916 - - diff --git a/Demo/SGTabs/main.m b/Demo/SGTabs/main.m index 1a4a512..e75aee8 100644 --- a/Demo/SGTabs/main.m +++ b/Demo/SGTabs/main.m @@ -3,7 +3,7 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// Copyright (c) 2012 Simon Grätzer. All rights reserved. // #import diff --git a/README.md b/README.md index e49f12c..c2fa2bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,24 @@ -SGTabs -====== +# SGTabs -Tab component for iOS 5+. You can show your ViewControllers in tabs, it is possible to add and remove tabs on the fly \ No newline at end of file +Tab component for iOS 5+. You can show your ViewControllers in tabs, it is possible to add and remove tabs on the fly + + + +# Licence +I provider my code under the Apache Licence. +Credits go to [Fictorial LLC][https://github.com/fictorial/BHTabBar], my tab control implementation is spired by BHTabBar + + + Copyright 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. \ No newline at end of file diff --git a/Source/SGTabView.h b/Source/SGTabView.h index 0d8f413..a535f2b 100644 --- a/Source/SGTabView.h +++ b/Source/SGTabView.h @@ -3,8 +3,23 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. // +// +// 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. +// + #import @@ -14,7 +29,7 @@ } @property (nonatomic, strong) UILabel *titleLabel; -@property (nonatomic, assign) NSUInteger index; +@property (nonatomic, assign) NSUInteger position; @property (nonatomic, assign) BOOL editable; - (id)initWithFrame:(CGRect)frame title:(NSString *)title; diff --git a/Source/SGTabView.m b/Source/SGTabView.m index 424b82d..e8b0ddb 100644 --- a/Source/SGTabView.m +++ b/Source/SGTabView.m @@ -3,18 +3,32 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGTabView.h" #import -#define kRadius 7.5 +#define kRadius 10.0 #define kMargin 0.0 @implementation SGTabView -@synthesize titleLabel, index, editable; +@synthesize titleLabel, position, editable; - (CGRect)tabRect { return CGRectMake(self.bounds.origin.x + kMargin, @@ -86,7 +100,7 @@ - (void)drawRect:(CGRect)rect { CGContextSaveGState(context); CGContextAddPath(context, path); CGContextSetFillColorWithColor(context, startColor); - CGContextSetShadow(context, CGSizeMake(0, -1), 3.0); + CGContextSetShadow(context, CGSizeMake(0, 5), 3.0); CGContextFillPath(context); CGContextRestoreGState(context); diff --git a/Source/SGTabsTopView.h b/Source/SGTabsTopView.h index 117f89e..a49b387 100644 --- a/Source/SGTabsTopView.h +++ b/Source/SGTabsTopView.h @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import diff --git a/Source/SGTabsTopView.m b/Source/SGTabsTopView.m index 0dd476a..8d7d393 100644 --- a/Source/SGTabsTopView.m +++ b/Source/SGTabsTopView.m @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGTabsTopView.h" diff --git a/Source/SGTabsView.h b/Source/SGTabsView.h index 29cc3d1..17d1a15 100644 --- a/Source/SGTabsView.h +++ b/Source/SGTabsView.h @@ -3,19 +3,37 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import @class SGTabsViewController; -@interface SGTabsView : UIView +@interface SGTabsView : UIView { + CGPoint _original; +} @property (nonatomic, weak) SGTabsViewController *tabsController; @property (nonatomic, strong) NSMutableArray *tabs; +@property (nonatomic, assign) NSUInteger selected; - (void)addTab:(NSString *)title; +- (void)removeTab:(NSUInteger)index; /// Calculates the width each tabs needs and resizes the view - (void)resizeTabs; diff --git a/Source/SGTabsView.m b/Source/SGTabsView.m index 0da3591..a9a8941 100644 --- a/Source/SGTabsView.m +++ b/Source/SGTabsView.m @@ -3,42 +3,47 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGTabsView.h" #import "SGTabView.h" #import "SGTabsViewController.h" -#define MARGIN 2.5 +#define kMARGIN 2.5 @interface SGTabsView () - (CGFloat)tabWidth:(NSUInteger)count; @end @implementation SGTabsView -@synthesize tabs = _tabs, tabsController; +@synthesize tabs = _tabs, tabsController, selected = _selected; - (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; } return self; } -- (CGFloat)tabWidth:(NSUInteger)count { - CGFloat width; - if (count > 0) - width = (self.bounds.size.width - 2*MARGIN)/count; - else - width = 300.0; - return MIN(width, 300.0); -} - - (NSMutableArray *)tabs { if (!_tabs) { _tabs = [[NSMutableArray alloc] initWithCapacity:[self.tabsController maxTabs]]; @@ -46,47 +51,155 @@ - (NSMutableArray *)tabs { return _tabs; } +#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 - MARGIN); + 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.editableTabs; - CGFloat cap = 5.0/width; - newTab.contentStretch = CGRectMake(cap, 0.0, 1.0, 1-cap); + newTab.position = self.tabs.count; + newTab.editable = self.tabsController.editable; + + UITapGestureRecognizer *tapG = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + tapG.numberOfTapsRequired = 1; + tapG.numberOfTouchesRequired = 1; + [newTab addGestureRecognizer:tapG]; + + UIPanGestureRecognizer *panG = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; + [newTab addGestureRecognizer:panG]; + +// CGFloat cap = 7.5/width; +// newTab.contentStretch = CGRectMake(cap, 0.0, 1.0, 1-cap); + _selected = self.tabs.count; [self.tabs addObject:newTab]; [UIView transitionWithView:self duration:0.5 options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionCurveEaseInOut animations:^{ - [self addSubview:newTab]; - - for (int i = 0; i < self.tabs.count; i++) { - SGTabView *tab = [self.tabs objectAtIndex:i]; - tab.frame = CGRectMake(width*i + MARGIN, 0, width, self.bounds.size.height - MARGIN); + for (SGTabView *tab in self.tabs) { + tab.frame = CGRectMake(width*tab.position + kMARGIN, 0, width, self.bounds.size.height - kMARGIN); + if (tab.position == newTab.position) { + tab.alpha = 1.0; + [self bringSubviewToFront:tab]; + } else + tab.alpha = 0.6; + } + } + completion:NULL]; +} + +- (void)removeTab:(NSUInteger)index { + SGTabView *oldTab = [self.tabs objectAtIndex:index]; + [self.tabs removeObject:oldTab]; + CGFloat width = [self tabWidth:self.tabs.count]; + + [UIView transitionWithView:self + duration:0.5 + options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionCurveEaseInOut + animations:^{ + [oldTab removeFromSuperview]; + for (SGTabView *tab in self.tabs) { + if (tab.position > index) { + tab.position--; + } + tab.frame = CGRectMake((width)*tab.position + kMARGIN, 0, width, self.bounds.size.height - kMARGIN); } } completion:NULL]; } +- (void)setSelected:(NSUInteger)selected { + if (_selected != selected) { + _selected = selected; + NSUInteger selectedPosition = [[self.tabs objectAtIndex:selected] position]; + for (SGTabView *tab in self.tabs) { + if (tab.position == selectedPosition) { + tab.alpha = 1.0; + [self bringSubviewToFront:tab]; + } else { + tab.alpha = 0.6; + } + } + } + +} + +#pragma mark - Helpers + +- (CGFloat)tabWidth:(NSUInteger)count { + CGFloat width; + if (count > 0) + width = (self.bounds.size.width - 2*kMARGIN)/count; + else + width = 300.0; + return MIN(width, 300.0); +} + + - (void)resizeTabs { CGFloat width = [self tabWidth:self.tabs.count]; - for (int i = 0; i < self.tabs.count; i++) { - SGTabView *tab = [self.tabs objectAtIndex:i]; - tab.frame = CGRectMake(width*i + MARGIN, 0, width, self.bounds.size.height - MARGIN); + for (SGTabView *tab in self.tabs) + tab.frame = CGRectMake(width*tab.position + kMARGIN, 0, width, self.bounds.size.height - kMARGIN); +} + +#pragma mark - Gestures + +- (void)handleTap:(UITapGestureRecognizer *)sender { + if (sender.state == UIGestureRecognizerStateEnded) { + NSUInteger index = [self.tabs indexOfObject:sender.view]; + [self.tabsController showTab:index]; } } -/* -// Only override drawRect: if you perform custom drawing. -// An empty implementation adversely affects performance during animation. -- (void)drawRect:(CGRect)rect -{ - // Drawing code +- (void)handlePan:(UIPanGestureRecognizer *)sender { + SGTabView *panTab = (SGTabView *)sender.view; + + if (sender.state == UIGestureRecognizerStateBegan) { + [self.tabsController showTab:[self.tabs indexOfObject:panTab]]; + } else if (sender.state == UIGestureRecognizerStateChanged) { + CGPoint position = [sender translationInView:self]; + CGPoint center = CGPointMake(sender.view.center.x + position.x, sender.view.center.y); + + // Don't move the tab out of the view + if (center.x < self.bounds.size.width - kMARGIN && center.x > kMARGIN) { + sender.view.center = center; + [sender setTranslation:CGPointZero inView:self]; + + CGFloat width = [self tabWidth:self.tabs.count]; + // If more than half the tab width is moved, switch the positions + if (abs(center.x - width*panTab.position - width/2) > width/2) { + + NSUInteger nextPos = position.x > 0 ? panTab.position+1 : panTab.position-1; + SGTabView *next; + // Search the tab on the position next to the dragged one + for (SGTabView *tab in self.tabs) { + if (tab.position == nextPos) { + next = tab; + break; + } + } + if (next) { + next.position = panTab.position; + panTab.position = nextPos; + + [UIView animateWithDuration:0.5 animations:^{ + next.frame = CGRectMake(width*next.position + kMARGIN, 0, width, self.bounds.size.height - kMARGIN); + }]; + } + } + } + + } else if (sender.state == UIGestureRecognizerStateEnded) { + CGPoint velocity = [sender velocityInView:self]; + [UIView animateWithDuration:0.5 animations:^{ + // Let's give it 0.025 secnonds more + panTab.center = CGPointMake(panTab.center.x + velocity.x*0.025, panTab.center.y); + [self resizeTabs]; + }]; + } } -*/ @end diff --git a/Source/SGTabsViewController.h b/Source/SGTabsViewController.h index a17ce18..332a34b 100644 --- a/Source/SGTabsViewController.h +++ b/Source/SGTabsViewController.h @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import @@ -22,13 +36,16 @@ @interface SGTabsViewController : UIViewController { SGTabsTopView *_topView; SGTabsView *_tabsView; + BOOL _editable; } @property (nonatomic, weak) id delegate; -@property (nonatomic, assign) BOOL editableTabs; +@property (nonatomic, readonly) BOOL editable; @property (nonatomic, strong) SGTabsView *tabsView; +- (id)initEditable:(BOOL)editable; + /** Adds a blank tab * Reurns the id of the tab */ @@ -37,6 +54,8 @@ - (void)showTab:(NSUInteger)index; +- (void)removeTab:(NSUInteger)index; + - (NSUInteger)count; - (NSUInteger)maxTabs; diff --git a/Source/SGTabsViewController.m b/Source/SGTabsViewController.m index cd8222a..e6eeb0a 100644 --- a/Source/SGTabsViewController.m +++ b/Source/SGTabsViewController.m @@ -3,7 +3,21 @@ // SGTabs // // Created by simon on 07.06.12. -// Copyright (c) 2012 Cybercon GmbH. All rights reserved. +// +// +// 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. // #import "SGTabsViewController.h" @@ -19,13 +33,11 @@ @interface SGTabsViewController () @end @implementation SGTabsViewController -@synthesize delegate, editableTabs = _editableTabs, tabsView = _tabsView; +@synthesize delegate, editable = _editable, tabsView = _tabsView; -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) { - // Custom initialization +- (id)initEditable:(BOOL)editable { + if (self = [super init]) { + _editable = editable; } return self; } @@ -66,6 +78,7 @@ - (void)loadView { frame = CGRectMake(bounds.origin.x, kTabsTopViewHeigth, bounds.size.width, kTabsHeigth); _tabsView = [[SGTabsView alloc] initWithFrame:frame]; + _tabsView.tabsController = self; [self.view addSubview:_topView]; [self.view addSubview:_tabsView]; @@ -81,6 +94,10 @@ - (void)addTabwithContent:(UIViewController *)viewController { } - (void)showTab:(NSUInteger)index { + self.tabsView.selected = index; +} + +- (void)removeTab:(NSUInteger)index { } @@ -90,13 +107,6 @@ - (NSUInteger)maxTabs { return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 6 : 3; } -- (void)setEditableTabs:(BOOL)editableTabs { - for (SGTabView *tab in self.tabsView.tabs) { - tab.editable = editableTabs; - } - editableTabs = editableTabs; -} - - (NSUInteger)count { return self.tabsView.tabs.count; }