Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Classes/StandardTabItemsExampleController.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ - (void)tabView:(RKTabView *)tabView tabBecameDisabledAtIndex:(NSUInteger)index
NSLog(@"Tab № %tu became disabled on tab view", index);
}

- (void)tabView:(RKTabView *)tabView didTapOnEnabledItemAtIndex:(NSUInteger)index tab:(RKTabItem *)tabItem {
NSLog(@"Tab № %tu already enabled on tab view", index);
}

@end
2 changes: 1 addition & 1 deletion RKTabView.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Pod::Spec.new do |s|

s.platform = :ios, '5.0'
s.source = { :git => "https://github.com/RafaelKayumov/RKTabView.git", :tag => s.version }
s.source_files = 'RKTabView/RKTab{Item,View}.{h,m}'
s.source_files = 'RKTabView/RKTab{Item,View}.{h,m}', 'RKTabView/UIView+Badge.{h,m}'
s.requires_arc = true

end
6 changes: 6 additions & 0 deletions RKTabView.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
3A364D9B1B84ECD80097C65E /* UIView+Badge.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A364D9A1B84ECD80097C65E /* UIView+Badge.m */; };
780B526C183BB63C0009D12A /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 780B5268183BB63C0009D12A /* [email protected] */; };
780B526D183BB63C0009D12A /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 780B5269183BB63C0009D12A /* [email protected] */; };
780B526E183BB63C0009D12A /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 780B526A183BB63C0009D12A /* [email protected] */; };
Expand Down Expand Up @@ -58,6 +59,8 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
3A364D991B84ECD80097C65E /* UIView+Badge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Badge.h"; sourceTree = "<group>"; };
3A364D9A1B84ECD80097C65E /* UIView+Badge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Badge.m"; sourceTree = "<group>"; };
780B5268183BB63C0009D12A /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
780B5269183BB63C0009D12A /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
780B526A183BB63C0009D12A /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -232,6 +235,8 @@
78A7C6C8183A06B60075A7DD /* RKTabItem.m */,
78A7C6C9183A06B60075A7DD /* RKTabView.h */,
78A7C6C6183A06B60075A7DD /* RKTabView.m */,
3A364D991B84ECD80097C65E /* UIView+Badge.h */,
3A364D9A1B84ECD80097C65E /* UIView+Badge.m */,
);
path = RKTabView;
sourceTree = "<group>";
Expand Down Expand Up @@ -379,6 +384,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3A364D9B1B84ECD80097C65E /* UIView+Badge.m in Sources */,
780B5278183BC4D70009D12A /* StandardTabItemsExampleController.m in Sources */,
780B5299183BCB0B0009D12A /* UnexcludableTabsExampleController.m in Sources */,
78A7C6E0183A06D80075A7DD /* AppDelegate.m in Sources */,
Expand Down
11 changes: 7 additions & 4 deletions RKTabView/RKTabItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ typedef enum {
@property (nonatomic, strong) UIColor *titleFontColorEnabled;
@property (nonatomic, strong, readonly) UIImage *imageForCurrentState;

@property (nonatomic, assign) NSInteger badgeValue;
@property (nonatomic, assign) CGSize badgeOffset;

+ (RKTabItem *)createUsualItemWithImageEnabled:(UIImage *)imageEnabled
imageDisabled:(UIImage *)imageDisabled;
imageDisabled:(UIImage *)imageDisabled;

+ (RKTabItem *)createUnexcludableItemWithImageEnabled:(UIImage *)imageEnabled
imageDisabled:(UIImage *)imageDisabled;
imageDisabled:(UIImage *)imageDisabled;

+ (RKTabItem *)createButtonItemWithImage:(UIImage *)image
target:(id)target
selector:(SEL)selector;
target:(id)target
selector:(SEL)selector;

- (void)switchState;

Expand Down
17 changes: 13 additions & 4 deletions RKTabView/RKTabItem.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,47 @@ @interface RKTabItem ()
@implementation RKTabItem

+ (RKTabItem *)createUsualItemWithImageEnabled:(UIImage *)imageEnabled
imageDisabled:(UIImage *)imageDisabled {
imageDisabled:(UIImage *)imageDisabled {
RKTabItem *tabItem = [[RKTabItem alloc] init];
if (tabItem) {
tabItem.imageEnabled = imageEnabled;
tabItem.imageDisabled = imageDisabled;
tabItem.tabState = TabStateDisabled;
tabItem.tabType = TabTypeUsual;

tabItem.badgeValue = 0;
tabItem.badgeOffset = CGSizeZero;
}
return tabItem;
}

+ (RKTabItem *)createUnexcludableItemWithImageEnabled:(UIImage *)imageEnabled
imageDisabled:(UIImage *)imageDisabled {
imageDisabled:(UIImage *)imageDisabled {
RKTabItem *tabItem = [[RKTabItem alloc] init];
if (tabItem) {
tabItem.imageEnabled = imageEnabled;
tabItem.imageDisabled = imageDisabled;
tabItem.tabState = TabStateDisabled;
tabItem.tabType = TabTypeUnexcludable;

tabItem.badgeValue = 0;
tabItem.badgeOffset = CGSizeZero;
}
return tabItem;
}

+ (RKTabItem *)createButtonItemWithImage:(UIImage *)image
target:(id)target
selector:(SEL)selector {
target:(id)target
selector:(SEL)selector {
RKTabItem *tabItem = [[RKTabItem alloc] init];
if (tabItem) {
tabItem.imageEnabled = image;
tabItem.tabType = TabTypeButton;
tabItem.target = target;
tabItem.selector = selector;

tabItem.badgeValue = 0;
tabItem.badgeOffset = CGSizeZero;
}
return tabItem;
}
Expand Down
7 changes: 7 additions & 0 deletions RKTabView/RKTabView.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ static inline HorizontalEdgeInsets HorizontalEdgeInsetsMake (CGFloat left, CGFlo
- (void)tabView:(RKTabView *)tabView tabBecameEnabledAtIndex:(NSUInteger)index tab:(RKTabItem *)tabItem;
//Called Only for unexcludable items. (TabTypeUnexcludable)
- (void)tabView:(RKTabView *)tabView tabBecameDisabledAtIndex:(NSUInteger)index tab:(RKTabItem *)tabItem;
//Called Only for usual items. (TabTypeUsual)
- (void)tabView:(RKTabView *)tabView didTapOnEnabledItemAtIndex:(NSUInteger)index tab:(RKTabItem *)tabItem;

@end

Expand All @@ -39,9 +41,14 @@ static inline HorizontalEdgeInsets HorizontalEdgeInsetsMake (CGFloat left, CGFlo
@property (nonatomic, strong) NSArray *tabItems;
@property (nonatomic, readwrite) HorizontalEdgeInsets horizontalInsets;

@property (nonatomic, strong) UIFont *badgeTitleFont;
@property (nonatomic, strong) UIColor *badgeTitleColor;
@property (nonatomic, strong) UIColor *badgeBackgroundColor;

- (id)initWithFrame:(CGRect)frame andTabItems:(NSArray *)tabItems;

- (void)switchTabIndex:(NSUInteger)index;
- (void)setBadgeValue:(NSInteger)value forTabAtIndex:(NSUInteger)index;
- (RKTabItem *)selectedTabItem;

@end
79 changes: 72 additions & 7 deletions RKTabView/RKTabView.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#import "RKTabView.h"
#import "RkTabItem.h"
#import "UIView+Badge.h"

#define DARKER_BACKGROUND_VIEW_TAG 33

Expand Down Expand Up @@ -37,11 +38,11 @@ - (RKTabItem *)selectedTabItem {
NSUInteger selectedIndex = [self.tabItems indexOfObjectPassingTest:^BOOL(RKTabItem *obj, NSUInteger idx, BOOL *stop) {
return obj.tabState == TabStateEnabled;
}];

if (selectedIndex == NSNotFound) {
return nil;
}

RKTabItem *selectedItem = [self.tabItems objectAtIndex:selectedIndex];
return selectedItem;
}
Expand Down Expand Up @@ -91,6 +92,27 @@ - (UIColor *)upperSeparatorLineColor {
return _upperSeparatorLineColor;
}

- (UIColor *)badgeBackgroundColor {
if (!_badgeBackgroundColor) {
_badgeBackgroundColor = [UIColor redColor];
}
return _badgeBackgroundColor;
}

- (UIColor *)badgeTitleColor {
if (!_badgeTitleColor) {
_badgeTitleColor = [UIColor whiteColor];
}
return _badgeTitleColor;
}

- (UIFont *)badgeTitleFont {
if (!_badgeTitleFont) {
_badgeTitleFont = [UIFont italicSystemFontOfSize:15];
}
return _badgeTitleFont;
}

#pragma mark - Private

- (void)cleanTabView {
Expand All @@ -103,6 +125,7 @@ - (void)cleanTabView {
- (void)buildUI {
//clean before layout items
[self cleanTabView];

//build UI
for (RKTabItem *item in self.tabItems) {
UIControl *tab = [self tabForItem:item];
Expand Down Expand Up @@ -166,6 +189,13 @@ - (void)switchTab:(RKTabItem *)tabItem notify:(BOOL)notify {
}
}
}
else {
if (self.delegate) {
if ([self delegateRespondsToTapOnEnabledSelector] && notify) {
[self.delegate tabView:self didTapOnEnabledItemAtIndex:[self indexOfTab:tabItem] tab:tabItem];
}
}
}
[self setTabContent:tabItem];
break;
}
Expand All @@ -179,6 +209,13 @@ - (void)pressedTab:(id)sender {
[self switchTab:tabItem notify:YES];
}

- (void)setBadgeValue:(NSInteger)value forTabAtIndex:(NSUInteger)index {
if (index < self.tabItems.count) {
[(RKTabItem *)self.tabItems[index] setBadgeValue:value];
[self setTabContent:self.tabItems[index]];
}
}

#pragma mark - Helper methods

- (UIControl *)existingTabForTabItem:(RKTabItem *)tabItem {
Expand Down Expand Up @@ -217,7 +254,7 @@ - (CGRect)frameForTab:(RKTabItem *)tabItem {
- (void)setTabContent:(UIControl *)tab withTabItem:(RKTabItem *)tabItem {
//clean tab before setting content
for (UIView *subview in tab.subviews) {
if (subview != [tab viewWithTag:DARKER_BACKGROUND_VIEW_TAG]) {
if ((subview != [tab viewWithTag:DARKER_BACKGROUND_VIEW_TAG]) && (subview != tab.badge)) {
[subview removeFromSuperview];
}
}
Expand All @@ -230,7 +267,10 @@ - (void)setTabContent:(UIControl *)tab withTabItem:(RKTabItem *)tabItem {
titleLabel.numberOfLines = 2;
titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.adjustsLetterSpacingToFitWidth = YES;

//This was deprecated in iOS 7. If this is needed one can use the attributedString and adjust the NSKernAttributeName there.
//titleLabel.adjustsLetterSpacingToFitWidth = YES;

titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth;

UIFont *font = nil;
Expand All @@ -254,7 +294,10 @@ - (void)setTabContent:(UIControl *)tab withTabItem:(RKTabItem *)tabItem {
titleLabel.textColor = textColor;
titleLabel.backgroundColor = [UIColor clearColor];

titleSize = [tabItem.titleString sizeWithFont:titleLabel.font constrainedToSize:CGSizeMake(tab.bounds.size.width, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
titleSize = [tabItem.titleString boundingRectWithSize:CGSizeMake(tab.bounds.size.width, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: titleLabel.font}
context:nil].size;
titleLabel.text = tabItem.titleString;
}

Expand All @@ -273,8 +316,8 @@ - (void)setTabContent:(UIControl *)tab withTabItem:(RKTabItem *)tabItem {
//Subviews frames
if (titleLabel) {
CGFloat wholeGapHeight = tab.bounds.size.height - ((UIView *)interfaceElement).bounds.size.height - titleSize.height;
titleLabel.frame = CGRectMake(tab.bounds.size.width/2 - titleSize.width/2, wholeGapHeight*2/3+((UIView *)interfaceElement).bounds.size.height, titleSize.width+2, titleSize.height+2);
((UIView *)interfaceElement).frame = CGRectMake(tab.bounds.size.width/2 - ((UIView *)interfaceElement).bounds.size.width/2, wholeGapHeight/3, ((UIView *)interfaceElement).bounds.size.width, ((UIView *)interfaceElement).bounds.size.height);
titleLabel.frame = CGRectMake(tab.bounds.size.width/2 - titleSize.width/2, wholeGapHeight*2/4+((UIView *)interfaceElement).bounds.size.height, titleSize.width+2, titleSize.height+2);
((UIView *)interfaceElement).frame = CGRectMake(tab.bounds.size.width/2 - ((UIView *)interfaceElement).bounds.size.width/2, wholeGapHeight/2, ((UIView *)interfaceElement).bounds.size.width, ((UIView *)interfaceElement).bounds.size.height);
[tab addSubview:titleLabel];
} else {
((UIView *)interfaceElement).center = CGPointMake(tab.bounds.size.width/2, tab.bounds.size.height/2);
Expand Down Expand Up @@ -303,6 +346,9 @@ - (void)setTabContent:(UIControl *)tab withTabItem:(RKTabItem *)tabItem {
} else {
tab.backgroundColor = tabItem.backgroundColor ? tabItem.backgroundColor : [UIColor clearColor];
}

// Badge count
tab.badgeValue = [NSString stringWithFormat:@"%@", @(tabItem.badgeValue)];
}

- (void)setTabContent:(RKTabItem *)tabItem {
Expand Down Expand Up @@ -331,6 +377,16 @@ - (UIControl *)tabForItem:(RKTabItem *)tabItem {
[tab addSubview:darkerBackgroundView];
}

// Set up badge view
tab.badgeBGColor = self.badgeBackgroundColor;
tab.badgeTextColor = self.badgeTitleColor;
tab.badgeFont = self.badgeTitleFont;
tab.shouldHideBadgeAtZero = YES;
tab.shouldAnimateBadge = YES;
tab.badgeValue = [NSString stringWithFormat:@"%@", @(tabItem.badgeValue)];
tab.badgeOffsetX = tabItem.badgeOffset.width;
tab.badgeOffsetY = tabItem.badgeOffset.height;

//setup
[self setTabContent:tab withTabItem:tabItem];
}
Expand All @@ -355,6 +411,15 @@ - (BOOL)delegateRespondsToEnableSelector {
}
}

- (BOOL)delegateRespondsToTapOnEnabledSelector {
if ([self.delegate respondsToSelector:@selector(tabView:didTapOnEnabledItemAtIndex:tab:)]) {
return YES;
} else {
NSLog(@"Attention! Your delegate doesn't have tabView:didTapOnEnabledItemAtIndex:tab: method implementation!");
return NO;
}
}

#pragma mark - Drawing

- (void)drawRect:(CGRect)rect {
Expand Down
43 changes: 43 additions & 0 deletions RKTabView/UIView+Badge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// RKBadgeView.h
// RKTabView
//
// Created by Cao Tri DO on 19/08/2015.
// Copyright (c) 2015 Cao Tri DO. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UIView (Badge)

@property (strong, nonatomic) UILabel *badge;

// Badge value to be display
@property (nonatomic) NSString *badgeValue;

// Badge background color
@property (nonatomic) UIColor *badgeBGColor;

// Badge text color
@property (nonatomic) UIColor *badgeTextColor;

// Badge font
@property (nonatomic) UIFont *badgeFont;

// Padding value for the badge
@property (nonatomic) CGFloat badgePadding;

// Minimum size badge to small
@property (nonatomic) CGFloat badgeMinSize;

// Values for offseting the badge over the BarButtonItem you picked
@property (nonatomic) CGFloat badgeOffsetX;
@property (nonatomic) CGFloat badgeOffsetY;

// In case of numbers, remove the badge when reaching zero
@property BOOL shouldHideBadgeAtZero;

// Badge has a bounce animation when value changes
@property BOOL shouldAnimateBadge;

@end
Loading