Skip to content

Commit

Permalink
Added close button on a tab support
Browse files Browse the repository at this point in the history
  • Loading branch information
graetzer committed Jun 26, 2012
1 parent e0a5b36 commit b61cac4
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 67 deletions.
4 changes: 2 additions & 2 deletions Demo/SGTabs.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
F4068591159A5BF80001C064 /* SGTabsView.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2AB1580ECDB00ED3644 /* SGTabsView.m */; };
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 */; };
Expand All @@ -17,7 +18,6 @@
F470D2921580EA5100ED3644 /* SGViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2911580EA5100ED3644 /* SGViewController.m */; };
F470D2951580EA5100ED3644 /* SGViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F470D2931580EA5100ED3644 /* SGViewController.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 */; };
F470D2B21580ED3000ED3644 /* SGToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = F470D2B11580ED3000ED3644 /* SGToolbar.m */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -204,9 +204,9 @@
F470D28F1580EA5100ED3644 /* SGAppDelegate.m in Sources */,
F470D2921580EA5100ED3644 /* SGViewController.m in Sources */,
F470D2A91580EAD700ED3644 /* SGTabsViewController.m in Sources */,
F470D2AC1580ECDB00ED3644 /* SGTabsView.m in Sources */,
F470D2AF1580ECE700ED3644 /* SGTabView.m in Sources */,
F470D2B21580ED3000ED3644 /* SGToolbar.m in Sources */,
F4068591159A5BF80001C064 /* SGTabsView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
3 changes: 2 additions & 1 deletion Demo/SGTabs/SGAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
//

#import <UIKit/UIKit.h>
#import "SGTabsViewController.h"

@class SGTabsViewController;

@interface SGAppDelegate : UIResponder <UIApplicationDelegate> {
@interface SGAppDelegate : UIResponder <UIApplicationDelegate, SGTabsViewControllerDelegate> {
}

@property (strong, nonatomic) UIWindow *window;
Expand Down
7 changes: 5 additions & 2 deletions Demo/SGTabs/SGAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#import "SGAppDelegate.h"

#import "SGViewController.h"
#import "SGTabsViewController.h"

@implementation SGAppDelegate

Expand All @@ -35,7 +34,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.

self.tabController = [[SGTabsViewController alloc] initEditable:YES];
self.tabController = [[SGTabsViewController alloc] init];
self.tabController.delegate = self;
self.window.rootViewController = self.tabController;
[self.window makeKeyAndVisible];

Expand All @@ -53,4 +53,7 @@ - (void)openTab {
[self.tabController addTab:vc];
}

- (BOOL)canRemoveTab:(UIViewController *)viewController {
return self.tabController.count > 1;
}
@end
3 changes: 2 additions & 1 deletion Demo/SGTabs/SGTabs-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>wifi</string>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
Expand All @@ -36,9 +37,9 @@
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
</dict>
</plist>
1 change: 1 addition & 0 deletions Demo/SGTabs/SGTabs-Prefix.pch
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "SGTabsViewController.h"
#endif
17 changes: 3 additions & 14 deletions Demo/SGTabs/SGViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,9 @@ - (void)viewDidLoad
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:@selector(add:)];
UIBarButtonItem *trash = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
target:self
action:@selector(remove:)];
SGTabsViewController *tabs = (SGTabsViewController *) self.parentViewController;
if (tabs.count)
self.toolbarItems = [NSArray arrayWithObjects:space,urlBar,space2,trash,reload,add,nil];
else
self.toolbarItems = [NSArray arrayWithObjects:space,urlBar,space2,reload,add,nil];


self.toolbarItems = [NSArray arrayWithObjects:space,urlBar,space2,reload,add,nil];

}

Expand Down Expand Up @@ -109,11 +104,6 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}

- (IBAction)remove:(id)sender {
SGTabsViewController *tabs = (SGTabsViewController *) self.parentViewController;
[tabs removeViewController:self];
}

- (IBAction)reload:(id)sender {
[self.webView reload];
Expand All @@ -129,5 +119,4 @@ - (IBAction)add:(id)sender {
[tabs addTab:vc];

}

@end
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Tab component for iOS 5+. You can show your ViewControllers in tabs, it is possi
# 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
- User can remove tabs, if you allow it.
- Dynamically show and hide a UIToolbar at the top
- Show the UIBarButtonItems in viewController.toolbarItems in the toolbar
- Enables you to build mobile Safari style Apps. (See demo
- Enables you to build mobile Safari style Apps. (See demo)

# Demo
A basic web browser with tabs, in around 120 lines of code.
Expand Down
6 changes: 2 additions & 4 deletions Source/SGTabDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@
#define kTabsToolbarHeigthFull 44.0
#define kTabsHeigth 35.0

#define kCornerRadius 7.5
#define kCornerRadius 5.0

#define kShadowRadius 6.0
#define kShadowRadius 5.0

//[[UIColor alloc] initWithWhite:0.85 alpha:1.0]
#define kTabColor [UIColor colorWithRed:168./255. green:172./255. blue:185./255. alpha:1.0]
#define kTabUnselectedColor [[UIColor alloc] initWithWhite:0.7 alpha:1.0]
//[[UIColor alloc] initWithWhite:0.6 alpha:1]

#endif
2 changes: 2 additions & 0 deletions Source/SGTabView.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@

@interface SGTabView : UIView {
CGSize _tSize;
CGFloat _cap;
}

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIColor *tabColor;
@property (nonatomic, strong) UIButton *closeButton;

- (id)initWithFrame:(CGRect)frame title:(NSString *)title;

Expand Down
55 changes: 36 additions & 19 deletions Source/SGTabView.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

@interface SGTabView ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *closeButton;

@end

@implementation SGTabView
Expand All @@ -37,13 +37,14 @@ @implementation SGTabView

- (id)initWithFrame:(CGRect)frame title:(NSString *)title
{
self = [super initWithFrame:frame];
if (self) {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
CGFloat cap = kCornerRadius/frame.size.width;
self.contentStretch = CGRectMake(cap, 0.0, 1.0, 1-cap);
self.tabColor = kTabColor;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;

_cap = kCornerRadius/frame.size.width;
self.contentStretch = CGRectMake(_cap, 0.0, 1.0, 1-_cap);


self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.titleLabel.textAlignment = UITextAlignmentCenter;
Expand All @@ -55,28 +56,44 @@ - (id)initWithFrame:(CGRect)frame title:(NSString *)title
self.titleLabel.textColor = [UIColor darkGrayColor];
self.titleLabel.shadowColor = [UIColor colorWithWhite:0.6 alpha:0.5];
self.titleLabel.shadowOffset = CGSizeMake(0, 0.5);

self.title = title;
[self addSubview:self.titleLabel];


// 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.closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.closeButton setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[self.closeButton setTitle:@"x" forState:UIControlStateNormal];
[self.closeButton setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[self.closeButton setShowsTouchWhenHighlighted:YES];
self.closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:16.0];
[self addSubview:self.closeButton];
}
return self;
}

- (void)layoutSubviews {
CGSize t = _tSize;
if (t.width > self.bounds.size.width*0.75)
t.width = self.bounds.size.width*0.75;
CGRect b = self.bounds;
self.titleLabel.frame = CGRectMake((b.size.width - t.width)/2,
(b.size.height - t.height)/2,
t.width, t.height);
CGFloat margin = _cap*b.size.width*2;

CGSize t = _tSize;
if (t.width > b.size.width*0.75) {
t.width = b.size.width*0.75;

if(!self.closeButton.hidden) {
self.titleLabel.frame = CGRectMake((b.size.width - t.width)/2 - margin,
(b.size.height - t.height)/2,
t.width - margin, t.height);
} else {
self.titleLabel.frame = CGRectMake((b.size.width - t.width)/2,
(b.size.height - t.height)/2,
t.width, t.height);
}
} else {
self.titleLabel.frame = CGRectMake((b.size.width - t.width)/2,
(b.size.height - t.height)/2,
t.width, t.height);
}

self.closeButton.frame = CGRectMake(b.size.width - 2*margin - 25, 0, 25, b.size.height);
}

- (void)setTitle:(NSString *)title {
Expand Down
39 changes: 36 additions & 3 deletions Source/SGTabsView.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ - (void)layoutSubviews{
- (void)addTab:(NSString *)title {
CGFloat width = [self tabWidth:self.tabs.count+1];

// Float the subview in from rigth
CGRect frame = CGRectMake(self.bounds.size.width, 0, width, self.bounds.size.height - kMARGIN);
SGTabView *newTab = [[SGTabView alloc] initWithFrame:frame title:title];
//newTab.closeButton.hidden = !self.tabsController.editing;

// Setup gesture recognizers
UITapGestureRecognizer *tapG = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTap:)];
tapG.numberOfTapsRequired = 1;
Expand All @@ -76,19 +77,33 @@ - (void)addTab:(NSString *)title {
panG.delegate = self;
[newTab addGestureRecognizer:panG];

// Setup close button
[newTab.closeButton addTarget:self action:@selector(handleRemove:) forControlEvents:UIControlEventTouchCancel];

// Add the tab
_selected = self.tabs.count;
[self.tabs addObject:newTab];

[self addSubview:newTab];
for (int i = 0; i < self.tabs.count; i++) {
SGTabView *tab = [self.tabs objectAtIndex:i];
// By setting the real position after the view is added, we create a float from rigth transition
tab.frame = CGRectMake(width*i + kMARGIN, 0, width, self.bounds.size.height - kMARGIN);
if (i == self.tabs.count-1) {
if (i == _selected) {
if ([self.tabsController.delegate respondsToSelector:@selector(canRemoveTab:)]) {
tab.closeButton.hidden = ![self.tabsController.delegate canRemoveTab:[self.tabsController.tabContents objectAtIndex:i]];
} else {
tab.closeButton.hidden = NO;
}

tab.alpha = 1.0;
[self bringSubviewToFront:tab];
} else {
tab.closeButton.hidden = YES;
tab.alpha = 0.7;
[tab setNeedsLayout];
}

[tab setNeedsDisplay];
}
}
Expand All @@ -107,10 +122,19 @@ - (void)setSelected:(NSUInteger)selected {
for (int i = 0; i < self.tabs.count; i++) {
SGTabView *tab = [self.tabs objectAtIndex:i];
if (i == selected) {
if ([self.tabsController.delegate respondsToSelector:@selector(canRemoveTab:)]) {
tab.closeButton.hidden = ![self.tabsController.delegate canRemoveTab:[self.tabsController.tabContents objectAtIndex:i]];
} else {
tab.closeButton.hidden = NO;
}

tab.alpha = 1.0;
[tab setNeedsLayout];
[self bringSubviewToFront:tab];
} else {
tab.closeButton.hidden = YES;
tab.alpha = 0.7;
[tab setNeedsLayout];
}
[tab setNeedsDisplay];
}
Expand All @@ -133,7 +157,16 @@ - (void)resizeTabs {
}
}

#pragma mark - Gestures
#pragma mark - Actions

- (IBAction)handleRemove:(id)sender {
NSLog(@"%s", __PRETTY_FUNCTION__);
UIView *v = sender;
NSUInteger index = [self.tabs indexOfObject:v.superview];
if (index != NSNotFound) {
[self.tabsController removeIndex:index];
}
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return NO;
Expand Down
6 changes: 1 addition & 5 deletions Source/SGTabsViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,25 @@
@optional
- (void)willShowTab:(UIViewController *)viewController;
- (void)willRemoveTab:(UIViewController *)viewController;
- (BOOL)canRemoveTab:(UIViewController *)viewController;// TODO
- (BOOL)canRemoveTab:(UIViewController *)viewController;

@end

@class SGToolbar, SGTabsView;

@interface SGTabsViewController : UIViewController {
BOOL _editable;
CGRect _contentFrame;
BOOL _toobarVisible;
}

/// Is an optional delegate
@property (nonatomic, weak) id<SGTabsViewControllerDelegate> delegate;
@property (nonatomic, readonly) BOOL editable;

/// Currently visible view controller
@property (nonatomic, readonly, weak) UIViewController *currentViewController;

@property (nonatomic, readonly, strong) NSMutableArray *tabContents;

- (id)initEditable:(BOOL)editable;

/// Adds a tab, don't add the same instance twice!
- (void)addTab:(UIViewController *)viewController;

Expand Down
Loading

0 comments on commit b61cac4

Please sign in to comment.