iOS自定义TabBarViewController

UITabBarController 虽然很强大,基本上也能满足常见的需求,但是用起来总没那么畅快。有时候,总有一些变态的需求,需要自定义。

之前也看过一些别人自定义的TabBarController,但是都不尽理想,准确的说,很多自定义的都是继承自UITabBarController的即是半自定义的。根本谈不上真正意义上的自定义。

今天就分析一个我认为比较好的自定义TabBarController.

一,先来看一下TabBarController的基本结构

一般说来TabBarController,下面有一个TabBar, TabBar是一个视图,继承自UIView.
TabBar这个视图里面又有多个选项TabBarItem,这些个Item,是一个可以点击,并且可以切换到对应的控制器页面的按键,同时,这些按键还有自己本身的属性设置。所以Item应该继承自UIControl. 所以结构就很清楚了:分3个部分。
  • TabBarController (继承自UIViewController)
  • TabBar    (继承自UIView)
  • TabBarItem       (继承自UIControl)

二,分别来封装和分析各个部分

1. 先来看TabBarItem

tabBarItem,直观的显示,就是我们看到那几个点击来回切换的按键。当点击每一个选项的时候,选项就会有相应的变化,同时切换到对应的控制器界面。
有哪些属性和变化呢?

  a. 本身基本属性:有选中/未选中图片、选中/未选中文字及颜色、选中/未选中背景色、有宽高大小位置偏移(供微调用);

  b. 徽标显示:徽标值及其颜色大小、徽标图片、背景色

  

#import 

@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 

@class RDVTabBar, RDVTabBarItem;

@protocol RDVTabBarDelegate 

/**
 * 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  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

3. 最后来看TabBarController

TabBarController 里面有TabBar, 有默认选项,tabBarItem对应的View Controllers及其之间的关联。还有一些代理方法。故而

#import 
#import "RDVTabBar.h"

@protocol RDVTabBarControllerDelegate;

@interface RDVTabBarController : UIViewController 

/**
 * The tab bar controller’s delegate object.
 */
@property (nonatomic, weak) id 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 
@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

重点分析一下, 当点击TabBarItem的时候,如何关联控制器的。

其实就是通过导航控制器来切换到对应编号的视图控制器。请看核心代码

- (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

你可能感兴趣的:(iOS自定义TabBarViewController)