【iOS】自訂TabBarController

來源:互聯網
上載者:User

一、自訂的思路

iOS中的TabBarController確實已經很強大了,大部分主流iOS應用都會採用。但是往往也不能滿足全部的需求,因此需要自訂TabBar,自訂需要對系統的TabBar工作方式有很好的理解,自訂需要勇氣。

自訂TabBar的原則:盡量利用系統內建TabBar,只改需要改的地方。


二、自訂TabBar的總體過程1.先把內建的TabBar條給取消了2.自己做一個view,上面放幾個按鈕,設定按鈕的點擊事件.並設定selectIndex。3.關聯各個子viewController,覆蓋相關事件。

三、細節很重要

1. 讓自己建立的按鈕關聯到viewController:•用tabbar的selectedIndex屬性.設定這個屬性就行了.2. 取消系統的高亮:•可以自訂一個按鈕.重寫裡面的setHighhighted方法,什麼也不做就行了.(如果調用super就相當於沒寫)3. 關於幾個按鈕只選中一個的方法:•設定一個屬性,記錄上一個選中的按鈕.•點擊當前按鈕時,把上一個按鈕設定為未選中,並把當前按鈕設定為選中,最後把當前按鈕賦值給上一個按鈕.
四、初步自訂直接上代碼,詳見注釋。 XNTabBarController.h

#import <UIKit/UIKit.h>@interface XNTabBarController : UITabBarController@end

XNTabBarController.m

////  XNTabBarController.m//////  Created by neng on 14-6-19.//  Copyright (c) 2014年 neng. All rights reserved.//#import "XNTabBarController.h"#import "Common.h"#import "XNTabBarButton.h"@interface XNTabBarController ()/** *  設定之前選中的按鈕 */@property (nonatomic, weak) UIButton *selectedBtn;@end@implementation XNTabBarController- (void)viewDidLoad {[super viewDidLoad];//下面兩個方法在開發中是經常會用到的//    NSLog(@"%s",__func__);//    NSLog(@"%@",self.view.subviews); //能列印出所有子視圖,和其frameLogFun;LogSubviews(self.view);//刪除現有的tabBarCGRect rect = self.tabBar.frame;[self.tabBar removeFromSuperview];  //移除TabBarController內建的下部的條//測試添加自己的視圖UIView *myView = [[UIView alloc] init];myView.frame = rect;myView.backgroundColor = [UIColor redColor];[self.view addSubview:myView];for (int i = 0; i < 5; i++) {//UIButton *btn = [[UIButton alloc] init];        XNTabBarButton *btn = [[XNTabBarButton alloc] init];        NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];CGFloat x = i * myView.frame.size.width / 5;btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);[myView addSubview:btn];                btn.tag = i;//設定按鈕的標記, 方便來索引當前的按鈕,並跳轉到相應的視圖//帶參數的監聽方法記得加"冒號"[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];//設定剛進入時,第一個按鈕為選中狀態if (0 == i) {btn.selected = YES;self.selectedBtn = btn;  //設定該按鈕為選中的按鈕}}}/** *  自訂TabBar的按鈕點擊事件 */- (void)clickBtn:(UIButton *)button {//1.先將之前選中的按鈕設定為未選中self.selectedBtn.selected = NO;//2.再將當前按鈕設定為選中button.selected = YES;//3.最後把當前按鈕賦值為之前選中的按鈕self.selectedBtn = button;        //4.跳轉到相應的視圖控制器. (通過selectIndex參數來設定選中了那個控制器)    self.selectedIndex = button.tag;}@end

XNTabBarButton.h

#import <UIKit/UIKit.h>@interface XNTabBarButton : UIButton@end

XNTabBarButton.m

#import "XNTabBarButton.h"@implementation XNTabBarButton/**什麼也不做就可以取消系統按鈕的高亮狀態*/- (void)setHighlighted:(BOOL)highlighted{//    [super setHighlighted:highlighted];}@end

五、代碼重構

重構的目的是把代碼放到他最該到的地方去. 提高可讀寫與可拓展性。
對控制項的重構要保證可重用性. 做到封裝做其他應用時,可以直接拿過去用的地步.
tips :1、關於init與initWithFrame:•在對象初始化調用init時,會調用initWithFrame方法.•Init與initWithFrame都會被調用.•建議自訂控制項不要重寫init方法,需要初始化時重寫initWithFrame方法.•好處:其他人調用無論是調用init,還是調用initWithFrame都會調用initWithFrame方法.

2、關於控制項的布局代碼:•建議寫在layoutSubviews方法中.•不要忘記寫super方法•將設定x,y,frame等寫在這裡面.3、將自訂的Tabbar添加為系統TabBar的子視圖,這樣TabBar的切換自動隱藏/滑動功能就不用自己做了. (hidebottombaronpush)
重構後的代碼如下:將自訂的TabBar單獨建立,並將代碼移過去。設定代理方法,工具列按鈕被選中,記錄從哪裡跳轉到哪裡. 
XNTabBar.h

#import <UIKit/UIKit.h>@class XNTabBar;@protocol XNTabBarDelegate <NSObject>/** *  工具列按鈕被選中, 記錄從哪裡跳轉到哪裡. (方便以後做相應特效) */- (void) tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger) from to:(NSInteger)to;@end@interface XNTabBar : UIView@property(nonatomic,weak) id<XNTabBarDelegate> delegate;/** *  使用特定圖片來建立按鈕, 這樣做的好處就是可擴充性. 拿到別的項目裡面去也能換圖片直接用 * *  @param image         普通狀態下的圖片 *  @param selectedImage 選中狀態下的圖片 */-(void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *) selectedImage;@end


XNTabBar.m


////  XNTabBar.m////  Created by neng on 14-6-19.//  Copyright (c) 2014年 neng. All rights reserved.//#import "XNTabBar.h"#import "XNTabBarButton.h"@interface XNTabBar ()/** *  設定之前選中的按鈕 */@property (nonatomic, weak) UIButton *selectedBtn;@end@implementation XNTabBar/** *  在這個方法裡寫控制項初始化的東西, 調用init方法時會調用 *///- (id)initWithFrame:(CGRect)frame {//if (self = [super initWithFrame:frame]) {////添加按鈕//for (int i = 0; i < 5; i++) { //取消掉特定的數字////UIButton *btn = [[UIButton alloc] init];//XNTabBarButton *btn = [[XNTabBarButton alloc] init];////NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];//NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];////[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];//[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];////[self addSubview:btn];////btn.tag = i; //設定按鈕的標記, 方便來索引當前的按鈕,並跳轉到相應的視圖//////帶參數的監聽方法記得加"冒號"//[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];////if (0 == i) {//[self clickBtn:btn];//}//}//}//return self;//}- (void)addButtonWithImage:(UIImage *)image selectedImage:(UIImage *)selectedImage {UIButton *btn = [[UIButton alloc] init];[btn setImage:image forState:UIControlStateNormal];[btn setImage:selectedImage forState:UIControlStateSelected];[self addSubview:btn];//帶參數的監聽方法記得加"冒號"[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];//如果是第一個按鈕, 則選中(按順序一個個添加)if (self.subviews.count == 1) {[self clickBtn:btn];}}/**專門用來布局子視圖, 別忘了調用super方法*/- (void)layoutSubviews {[super layoutSubviews];int count = self.subviews.count;for (int i = 0; i < count; i++) {//取得按鈕UIButton *btn = self.subviews[i];btn.tag = i; //設定按鈕的標記, 方便來索引當前的按鈕,並跳轉到相應的視圖CGFloat x = i * self.bounds.size.width / count;CGFloat y = 0;CGFloat width = self.bounds.size.width / count;CGFloat height = self.bounds.size.height;btn.frame = CGRectMake(x, y, width, height);}}/** *  自訂TabBar的按鈕點擊事件 */- (void)clickBtn:(UIButton *)button {//1.先將之前選中的按鈕設定為未選中self.selectedBtn.selected = NO;//2.再將當前按鈕設定為選中button.selected = YES;//3.最後把當前按鈕賦值為之前選中的按鈕self.selectedBtn = button;//卻換視圖控制器的事情,應該交給controller來做//最好這樣寫, 先判斷該代理方法是否實現if ([self.delegate respondsToSelector:@selector(tabBar:selectedFrom:to:)]) {[self.delegate tabBar:self selectedFrom:self.selectedBtn.tag to:button.tag];}//4.跳轉到相應的視圖控制器. (通過selectIndex參數來設定選中了那個控制器)//self.selectedIndex = button.tag;}@end

原先的 XNTabBarController.m經過修改後,注釋了原先的代碼。

////  XNTabBarController.m////  Created by neng on 14-6-19.//  Copyright (c) 2014年 neng. All rights reserved.//#import "XNTabBarController.h"#import "XNTabBarButton.h"#import "XNTabBar.h"@interface XNTabBarController () <XNTabBarDelegate>/** *  設定之前選中的按鈕 */@property (nonatomic, weak) UIButton *selectedBtn;@end@implementation XNTabBarController- (void)viewDidLoad {[super viewDidLoad];//下面兩個方法在開發中是經常會用到的//    NSLog(@"%s",__func__);//    NSLog(@"%@",self.view.subviews); //能列印出所有子視圖,和其frame//LogFun;//LogSubviews(self.view);//Hell//刪除現有的tabBarCGRect rect = self.tabBar.bounds; //這裡要用bounds來加, 否則會加到下面去.看不見    LogFrame(self.tabBar);//[self.tabBar removeFromSuperview];  //移除TabBarController內建的下部的條//測試添加自己的視圖XNTabBar *myView = [[XNTabBar alloc] init]; //設定代理必須改掉前面的類型,不能用UIViewmyView.delegate = self; //設定代理myView.frame = rect;[self.tabBar addSubview:myView]; //添加到系統內建的tabBar上, 這樣可以用的的事件方法. 而不必自己去寫        //為控制器添加按鈕    for (int i=0; i<self.viewControllers.count; i++) { //根據有多少個子視圖控制器來進行添加按鈕                NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];        NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];                UIImage *image = [UIImage imageNamed:imageName];        UIImage *imageSel = [UIImage imageNamed:imageNameSel];                [myView addButtonWithImage:image selectedImage:imageSel];    }    //    //添加按鈕//for (int i = 0; i < 5; i++) {////UIButton *btn = [[UIButton alloc] init];//        XNTabBarButton *btn = [[XNTabBarButton alloc] init];////NSString *imageName = [NSString stringWithFormat:@"TabBar%d", i + 1];//NSString *imageNameSel = [NSString stringWithFormat:@"TabBar%dSel", i + 1];////[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];//[btn setImage:[UIImage imageNamed:imageNameSel] forState:UIControlStateSelected];////CGFloat x = i * myView.frame.size.width / 5;//btn.frame = CGRectMake(x, 0, myView.frame.size.width / 5, myView.frame.size.height);////[myView addSubview:btn];////        btn.tag = i;//設定按鈕的標記, 方便來索引當前的按鈕,並跳轉到相應的視圖//////帶參數的監聽方法記得加"冒號"//[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];//////設定剛進入時,第一個按鈕為選中狀態//if (0 == i) {//btn.selected = YES;//self.selectedBtn = btn;  //設定該按鈕為選中的按鈕//}//}}/**永遠別忘記設定代理*/- (void)tabBar:(XNTabBar *)tabBar selectedFrom:(NSInteger)from to:(NSInteger)to {self.selectedIndex = to;}/** *  自訂TabBar的按鈕點擊事件 *///- (void)clickBtn:(UIButton *)button {////1.先將之前選中的按鈕設定為未選中//self.selectedBtn.selected = NO;////2.再將當前按鈕設定為選中//button.selected = YES;////3.最後把當前按鈕賦值為之前選中的按鈕//self.selectedBtn = button;////    //4.跳轉到相應的視圖控制器. (通過selectIndex參數來設定選中了那個控制器)//    self.selectedIndex = button.tag;//}@end

自訂後的:




例子源碼下載 : http://download.csdn.net/detail/xn4545945/7572263

轉載請註明出處:http://blog.csdn.net/xn4545945  



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.