UITabBarController 虽然很强大,基本上也能满足常见的需求,但是用起来总没那么畅快。有时候,总有一些变态的需求,需要自定义。
之前也看过一些别人自定义的TabBarController,但是都不尽理想,准确的说,很多自定义的都是继承自UITabBarController的即是半自定义的。根本谈不上真正意义上的自定义。
今天就分析一个我认为比较好的自定义TabBarController.
tabBarItem,直观的显示,就是我们看到那几个点击来回切换的按键。当点击每一个选项的时候,选项就会有相应的变化,同时切换到对应的控制器界面。
有哪些属性和变化呢?
a. 本身基本属性:有选中/未选中图片、选中/未选中文字及颜色、选中/未选中背景色、有宽高大小位置偏移(供微调用);
b. 徽标显示:徽标值及其颜色大小、徽标图片、背景色
#import <UIKit/UIKit.h> @interface RDVTabBarItem : UIControl /** * itemHeight is an optional property. When set it is used instead of tabBar's height. */ @property CGFloat itemHeight; #pragma mark - Title configuration /** * The title displayed by the tab bar item. */ @property (nonatomic, copy) NSString *title; /** * The offset for the rectangle around the tab bar item's title. */ @property (nonatomic) UIOffset titlePositionAdjustment; /** * For title's text attributes see * https://developer.apple.com/library/ios/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html */ /** * The title attributes dictionary used for tab bar item's unselected state. */ @property (copy) NSDictionary *unselectedTitleAttributes; /** * The title attributes dictionary used for tab bar item's selected state. */ @property (copy) NSDictionary *selectedTitleAttributes; #pragma mark - Image configuration /** * The offset for the rectangle around the tab bar item's image. */ @property (nonatomic) UIOffset imagePositionAdjustment; /** * The image used for tab bar item's selected state. */ - (UIImage *)finishedSelectedImage; /** * The image used for tab bar item's unselected state. */ - (UIImage *)finishedUnselectedImage; /** * Sets the tab bar item's selected and unselected images. */ - (void)setFinishedSelectedImage:(UIImage *)selectedImage withFinishedUnselectedImage:(UIImage *)unselectedImage; #pragma mark - Background configuration /** * The background image used for tab bar item's selected state. */ - (UIImage *)backgroundSelectedImage; /** * The background image used for tab bar item's unselected state. */ - (UIImage *)backgroundUnselectedImage; /** * Sets the tab bar item's selected and unselected background images. */ - (void)setBackgroundSelectedImage:(UIImage *)selectedImage withUnselectedImage:(UIImage *)unselectedImage; #pragma mark - Badge configuration /** * Text that is displayed in the upper-right corner of the item with a surrounding background. */ @property (nonatomic, copy) NSString *badgeValue; /** * Image used for background of badge. */ @property (strong) UIImage *badgeBackgroundImage; /** * Color used for badge's background. */ @property (strong) UIColor *badgeBackgroundColor; /** * Color used for badge's text. */ @property (strong) UIColor *badgeTextColor; /** * The offset for the rectangle around the tab bar item's badge. */ @property (nonatomic) UIOffset badgePositionAdjustment; /** * Font used for badge's text. */ @property (nonatomic) UIFont *badgeTextFont; @end
2. 再来看TabBar
tabBar是一个视图,自然有视图的基本属性,里面有多个tabBarItem,所以必然有items个数的属性;有事件响应,所以有代理抛出接口
#import <UIKit/UIKit.h> @class RDVTabBar, RDVTabBarItem; @protocol RDVTabBarDelegate <NSObject> /** * Asks the delegate if the specified tab bar item should be selected. */ - (BOOL)tabBar:(RDVTabBar *)tabBar shouldSelectItemAtIndex:(NSInteger)index; /** * Tells the delegate that the specified tab bar item is now selected. */ - (void)tabBar:(RDVTabBar *)tabBar didSelectItemAtIndex:(NSInteger)index; @end @interface RDVTabBar : UIView /** * The tab bar’s delegate object. */ @property (nonatomic, weak) id <RDVTabBarDelegate> delegate; /** * The items displayed on the tab bar. */ @property (nonatomic, copy) NSArray *items; /** * The currently selected item on the tab bar. */ @property (nonatomic, weak) RDVTabBarItem *selectedItem; /** * backgroundView stays behind tabBar's items. If you want to add additional views, * add them as subviews of backgroundView. */ @property (nonatomic, readonly) UIView *backgroundView; /* * contentEdgeInsets can be used to center the items in the middle of the tabBar. */ @property UIEdgeInsets contentEdgeInsets; /** * Sets the height of tab bar. */ - (void)setHeight:(CGFloat)height; /** * Returns the minimum height of tab bar's items. */ - (CGFloat)minimumContentHeight; /* * Enable or disable tabBar translucency. Default is NO. */ @property (nonatomic, getter=isTranslucent) BOOL translucent; @end
TabBarController 里面有TabBar, 有默认选项,tabBarItem对应的View Controllers及其之间的关联。还有一些代理方法。故而
#import <UIKit/UIKit.h> #import "RDVTabBar.h" @protocol RDVTabBarControllerDelegate; @interface RDVTabBarController : UIViewController <RDVTabBarDelegate> /** * The tab bar controller’s delegate object. */ @property (nonatomic, weak) id<RDVTabBarControllerDelegate> delegate; /** * An array of the root view controllers displayed by the tab bar interface. */ @property (nonatomic, copy) IBOutletCollection(UIViewController) NSArray *viewControllers; /** * The tab bar view associated with this controller. (read-only) */ @property (nonatomic, readonly) RDVTabBar *tabBar; /** * The view controller associated with the currently selected tab item. */ @property (nonatomic, weak) UIViewController *selectedViewController; /** * The index of the view controller associated with the currently selected tab item. */ @property (nonatomic) NSUInteger selectedIndex; /** * A Boolean value that determines whether the tab bar is hidden. */ @property (nonatomic, getter=isTabBarHidden) BOOL tabBarHidden; /** * Changes the visibility of the tab bar. */ - (void)setTabBarHidden:(BOOL)hidden animated:(BOOL)animated; @end @protocol RDVTabBarControllerDelegate <NSObject> @optional /** * Asks the delegate whether the specified view controller should be made active. */ - (BOOL)tabBarController:(RDVTabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController; /** * Tells the delegate that the user selected an item in the tab bar. */ - (void)tabBarController:(RDVTabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController; @end @interface UIViewController (RDVTabBarControllerItem) /** * The tab bar item that represents the view controller when added to a tab bar controller. */ @property(nonatomic, setter = rdv_setTabBarItem:) RDVTabBarItem *rdv_tabBarItem; /** * The nearest ancestor in the view controller hierarchy that is a tab bar controller. (read-only) */ @property(nonatomic, readonly) RDVTabBarController *rdv_tabBarController; @end
其实就是通过导航控制器来切换到对应编号的视图控制器。请看核心代码
- (BOOL)tabBar:(RDVTabBar *)tabBar shouldSelectItemAtIndex:(NSInteger)index { if ([[self delegate] respondsToSelector:@selector(tabBarController:shouldSelectViewController:)]) { if (![[self delegate] tabBarController:self shouldSelectViewController:[self viewControllers][index]]) { return NO; } } if ([self selectedViewController] == [self viewControllers][index]) { if ([[self selectedViewController] isKindOfClass:[UINavigationController class]]) { UINavigationController *selectedController = (UINavigationController *)[self selectedViewController]; if ([selectedController topViewController] != [selectedController viewControllers][0]) { [selectedController popToRootViewControllerAnimated:YES]; } } return NO; } return YES; }
限于篇幅,不直接贴出代码,
直接获取源码Demo:https://github.com/robbdimitrov/RDVTabBarController