一:主框架分析:ios
1:主框架的效果圖以下:底部有一個tabBar,點擊tabBar按鈕切換首頁,信息,發現 和我幾個界面。則考慮將UITabBarController做爲窗口的根視圖控制器,因此新建類繼承UITabBarController,用來封裝主框架數組
:app
2:封裝根視圖控制器UITabBarController的代碼:框架
1 #import "HMTabBarViewController.h" 2 #import "HMHomeViewController.h" 3 #import "HMMessageViewController.h" 4 #import "HMDiscoverViewController.h" 5 #import "HMProfileViewController.h" 6 #import "HMNavigationController.h" 7 #import "HMTabBar.h" 8 #import "HMComposeViewController.h" 9 #import "HMUserTool.h" 10 #import "HMAccount.h" 11 #import "HMAccountTool.h" 12 13 @interface HMTabBarViewController () <HMTabBarDelegate, UITabBarControllerDelegate> 14 @property (nonatomic, weak) HMHomeViewController *home; 15 @property (nonatomic, weak) HMMessageViewController *message; 16 @property (nonatomic, weak) HMProfileViewController *profile; 17 @property (nonatomic, weak) UIViewController *lastSelectedViewContoller; 18 @end 19 20 @implementation HMTabBarViewController 21 - (void)viewDidLoad 22 { 23 [super viewDidLoad]; 24 25 //1:本身設爲本身的代理,爲了監聽自身的改變 26 self.delegate = self; 27 28 //2:添加全部的子控制器 29 [self addAllChildVcs]; 30 31 //3:建立自定義tabbar 32 [self addCustomTabBar]; 33 34 //4:利用定時器得到用戶的未讀數 35 // NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(getUnreadCount) userInfo:nil repeats:YES]; 36 // [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 37 } 38 39 #pragma mark -- 當切換控制器時,監聽自身切換控制器 40 41 - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UINavigationController *)viewController 42 { 43 UIViewController *vc = [viewController.viewControllers firstObject]; 44 if ([vc isKindOfClass:[HMHomeViewController class]]) { 45 if (self.lastSelectedViewContoller == vc) { 46 [self.home refresh:YES]; 47 } else { 48 [self.home refresh:NO]; 49 } 50 } 51 52 self.lastSelectedViewContoller = vc; 53 } 54 55 #pragma mark -- 得到未讀數 56 57 - (void)getUnreadCount 58 { 59 // 1.請求參數 60 HMUnreadCountParam *param = [HMUnreadCountParam param]; 61 param.uid = [HMAccountTool account].uid; 62 63 // 2.得到未讀數 64 [HMUserTool unreadCountWithParam:param success:^(HMUnreadCountResult *result) { 65 // 顯示微博未讀數 66 if (result.status == 0) { 67 self.home.tabBarItem.badgeValue = nil; 68 } else { 69 self.home.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.status]; 70 } 71 72 // 顯示消息未讀數 73 if (result.messageCount == 0) { 74 self.message.tabBarItem.badgeValue = nil; 75 } else { 76 self.message.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.messageCount]; 77 } 78 79 // 顯示新粉絲數 80 if (result.follower == 0) { 81 self.profile.tabBarItem.badgeValue = nil; 82 } else { 83 self.profile.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d", result.follower]; 84 } 85 86 // 在圖標上顯示全部的未讀數 87 [UIApplication sharedApplication].applicationIconBadgeNumber = result.totalCount; 88 HMLog(@"總未讀數--%d", result.totalCount); 89 } failure:^(NSError *error) { 90 HMLog(@"得到未讀數失敗---%@", error); 91 }]; 92 } 93 94 /** 95 * 建立自定義tabbar 96 */ 97 - (void)addCustomTabBar 98 { 99 // 建立自定義tabbar 100 HMTabBar *customTabBar = [[HMTabBar alloc] init]; 101 customTabBar.tabBarDelegate = self; 102 // 更換系統自帶的tabbar 103 [self setValue:customTabBar forKeyPath:@"tabBar"]; 104 } 105 106 /** 107 * 添加全部的子控制器 108 */ 109 - (void)addAllChildVcs 110 { 111 HMHomeViewController *home = [[HMHomeViewController alloc] init]; 112 [self addOneChlildVc:home title:@"首頁" imageName:@"tabbar_home" selectedImageName:@"tabbar_home_selected"]; 113 self.home = home; 114 self.lastSelectedViewContoller = home; 115 116 HMMessageViewController *message = [[HMMessageViewController alloc] init]; 117 [self addOneChlildVc:message title:@"消息" imageName:@"tabbar_message_center" selectedImageName:@"tabbar_message_center_selected"]; 118 self.message = message; 119 120 HMDiscoverViewController *discover = [[HMDiscoverViewController alloc] init]; 121 [self addOneChlildVc:discover title:@"發現" imageName:@"tabbar_discover" selectedImageName:@"tabbar_discover_selected"]; 122 123 HMProfileViewController *profile = [[HMProfileViewController alloc] init]; 124 [self addOneChlildVc:profile title:@"我" imageName:@"tabbar_profile" selectedImageName:@"tabbar_profile_selected"]; 125 self.profile = profile; 126 } 127 128 /** 129 * 添加一個子控制器 130 * 131 * @param childVc 子控制器對象 132 * @param title 標題 133 * @param imageName 圖標 134 * @param selectedImageName 選中的圖標 135 */ 136 - (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName 137 { 138 // 設置標題 139 childVc.title = title; 140 141 // 設置圖標 142 childVc.tabBarItem.image = [UIImage imageWithName:imageName]; 143 144 // 設置tabBarItem的普通文字顏色 145 NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; 146 textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor]; 147 textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10]; 148 [childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal]; 149 150 // 設置tabBarItem的選中文字顏色 151 NSMutableDictionary *selectedTextAttrs = [NSMutableDictionary dictionary]; 152 selectedTextAttrs[NSForegroundColorAttributeName] = [UIColor orangeColor]; 153 [childVc.tabBarItem setTitleTextAttributes:selectedTextAttrs forState:UIControlStateSelected]; 154 155 // 設置選中的圖標 156 UIImage *selectedImage = [UIImage imageWithName:selectedImageName]; 157 if (iOS7) { 158 // 聲明這張圖片用原圖(別渲染) 159 selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 160 } 161 childVc.tabBarItem.selectedImage = selectedImage; 162 163 // 添加爲tabbar控制器的子控制器 164 HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:childVc]; 165 [self addChildViewController:nav]; 166 } 167 168 #pragma mark - HMTabBarDelegate 169 - (void)tabBarDidClickedPlusButton:(HMTabBar *)tabBar 170 { 171 // 彈出發微博控制器 172 HMComposeViewController *compose = [[HMComposeViewController alloc] init]; 173 HMNavigationController *nav = [[HMNavigationController alloc] initWithRootViewController:compose]; 174 [self presentViewController:nav animated:YES completion:nil]; 175 } 176 @end
3:封裝導航控制器的代碼:ide
#import <UIKit/UIKit.h> @interface HMNavigationController : UINavigationController @end
#import "HMNavigationController.h" @interface HMNavigationController () @end @implementation HMNavigationController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } /** * 當導航控制器的view建立完畢就調用 */ - (void)viewDidLoad { [super viewDidLoad]; // 清空彈出手勢的代理,就能夠恢復彈出手勢 self.interactivePopGestureRecognizer.delegate = nil; } /** * 當第一次使用這個類的時候調用1次 */ + (void)initialize { // 設置UINavigationBarTheme的主 [self setupNavigationBarTheme]; // 設置UIBarButtonItem的主題 [self setupBarButtonItemTheme]; } /** * 設置UINavigationBarTheme的主題 */ + (void)setupNavigationBarTheme { UINavigationBar *appearance = [UINavigationBar appearance]; // 設置導航欄背景 if (!iOS7) { [appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_background"] forBarMetrics:UIBarMetricsDefault]; } // 設置文字屬性 NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; textAttrs[UITextAttributeTextColor] = [UIColor blackColor]; // UITextAttributeFont --> NSFontAttributeName(iOS7) #warning 過時 : 並不表明不能用, 僅僅是有最新的方案能夠取代它 textAttrs[UITextAttributeFont] = HMNavigationTitleFont; // UIOffsetZero是結構體, 只要包裝成NSValue對象, 才能放進字典\數組中 textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero]; [appearance setTitleTextAttributes:textAttrs]; } /** * 設置UIBarButtonItem的主題 */ + (void)setupBarButtonItemTheme { // 經過appearance對象能修改整個項目中全部UIBarButtonItem的樣式 UIBarButtonItem *appearance = [UIBarButtonItem appearance]; /**設置文字屬性**/ // 設置普通狀態的文字屬性 NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; textAttrs[UITextAttributeTextColor] = [UIColor orangeColor]; textAttrs[UITextAttributeFont] = [UIFont systemFontOfSize:15]; textAttrs[UITextAttributeTextShadowOffset] = [NSValue valueWithUIOffset:UIOffsetZero]; [appearance setTitleTextAttributes:textAttrs forState:UIControlStateNormal]; // 設置高亮狀態的文字屬性 NSMutableDictionary *highTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs]; highTextAttrs[UITextAttributeTextColor] = [UIColor redColor]; [appearance setTitleTextAttributes:highTextAttrs forState:UIControlStateHighlighted]; // 設置不可用狀態(disable)的文字屬性 NSMutableDictionary *disableTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs]; disableTextAttrs[UITextAttributeTextColor] = [UIColor lightGrayColor]; [appearance setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled]; /**設置背景**/ // 技巧: 爲了讓某個按鈕的背景消失, 能夠設置一張徹底透明的背景圖片 [appearance setBackgroundImage:[UIImage imageWithName:@"navigationbar_button_background"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; } /** * 能攔截全部push進來的子控制器 */ - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { if (self.viewControllers.count > 0) { // 若是如今push的不是棧底控制器(最早push進來的那個控制器) viewController.hidesBottomBarWhenPushed = YES; // 設置導航欄按鈕 viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_back" highImageName:@"navigationbar_back_highlighted" target:self action:@selector(back)]; viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_more" highImageName:@"navigationbar_more_highlighted" target:self action:@selector(more)]; } [super pushViewController:viewController animated:animated]; } - (void)back { #warning 這裏用的是self, 由於self就是當前正在使用的導航控制器 [self popViewControllerAnimated:YES]; } - (void)more { [self popToRootViewControllerAnimated:YES]; } @end
4:封裝tabBar代碼:oop
#import <UIKit/UIKit.h> @class HMTabBar; @protocol HMTabBarDelegate <NSObject> @optional - (void)tabBarDidClickedPlusButton:(HMTabBar *)tabBar; @end @interface HMTabBar : UITabBar @property (nonatomic, weak) id<HMTabBarDelegate> tabBarDelegate; @end
#import "HMTabBar.h" @interface HMTabBar() @property (nonatomic, weak) UIButton *plusButton; @end @implementation HMTabBar - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { if (!iOS7) { self.backgroundImage = [UIImage imageWithName:@"tabbar_background"]; } self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_button_background"]; // 添加加號按鈕 [self setupPlusButton]; } return self; } /** * 添加加號按鈕 */ - (void)setupPlusButton { UIButton *plusButton = [[UIButton alloc] init]; // 設置背景 [plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button"] forState:UIControlStateNormal]; [plusButton setBackgroundImage:[UIImage imageWithName:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted]; // 設置圖標 [plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add"] forState:UIControlStateNormal]; [plusButton setImage:[UIImage imageWithName:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted]; [plusButton addTarget:self action:@selector(plusClick) forControlEvents:UIControlEventTouchUpInside]; // 添加 [self addSubview:plusButton]; self.plusButton = plusButton; } - (void)plusClick { HMLog(@"plusClick----"); // 通知代理 if ([self.tabBarDelegate respondsToSelector:@selector(tabBarDidClickedPlusButton:)]) { [self.tabBarDelegate tabBarDidClickedPlusButton:self]; } } /** * 佈局子控件 */ - (void)layoutSubviews { [super layoutSubviews]; // 設置plusButton的frame [self setupPlusButtonFrame]; // 設置全部tabbarButton的frame [self setupAllTabBarButtonsFrame]; } /** * 設置全部plusButton的frame */ - (void)setupPlusButtonFrame { self.plusButton.size = self.plusButton.currentBackgroundImage.size; self.plusButton.center = CGPointMake(self.width * 0.5, self.height * 0.5); } /** * 設置全部tabbarButton的frame */ - (void)setupAllTabBarButtonsFrame { int index = 0; // 遍歷全部的button for (UIView *tabBarButton in self.subviews) { // 若是不是UITabBarButton, 直接跳過 if (![tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) continue; // 根據索引調整位置 [self setupTabBarButtonFrame:tabBarButton atIndex:index]; // 索引增長 index++; } } /** * 設置某個按鈕的frame * * @param tabBarButton 須要設置的按鈕 * @param index 按鈕所在的索引 */ - (void)setupTabBarButtonFrame:(UIView *)tabBarButton atIndex:(int)index { // 計算button的尺寸 CGFloat buttonW = self.width / (self.items.count + 1); CGFloat buttonH = self.height; tabBarButton.width = buttonW; tabBarButton.height = buttonH; if (index >= 2) { tabBarButton.x = buttonW * (index + 1); } else { tabBarButton.x = buttonW * index; } tabBarButton.y = 0; } @end
5:封裝UIBarButtonItem:分類封裝佈局
//自定義圖片按鈕:常態,高亮狀態 #import <UIKit/UIKit.h> @interface UIBarButtonItem (Extension) + (UIBarButtonItem *)itemWithImageName:(NSString *)imageName highImageName:(NSString *)highImageName target:(id)target action:(SEL)action; @end
#import "UIBarButtonItem+Extension.h" @implementation UIBarButtonItem (Extension) + (UIBarButtonItem *)itemWithImageName:(NSString *)imageName highImageName:(NSString *)highImageName target:(id)target action:(SEL)action { UIButton *button = [[UIButton alloc] init]; [button setBackgroundImage:[UIImage imageWithName:imageName] forState:UIControlStateNormal]; [button setBackgroundImage:[UIImage imageWithName:highImageName] forState:UIControlStateHighlighted]; // 設置按鈕的尺寸爲背景圖片的尺寸 button.size = button.currentBackgroundImage.size; // 監聽按鈕點擊 [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; return [[UIBarButtonItem alloc] initWithCustomView:button]; } @end
6:封裝UIView的frame:分類封裝字體
#import <UIKit/UIKit.h> @interface UIView (Extension) @property (nonatomic, assign) CGFloat x; @property (nonatomic, assign) CGFloat y; @property (nonatomic, assign) CGFloat centerX; @property (nonatomic, assign) CGFloat centerY; @property (nonatomic, assign) CGFloat width; @property (nonatomic, assign) CGFloat height; @property (nonatomic, assign) CGSize size; @end
#import "UIView+Extension.h" @implementation UIView (Extension) - (void)setX:(CGFloat)x { CGRect frame = self.frame; frame.origin.x = x; self.frame = frame; } - (CGFloat)x { return self.frame.origin.x; } - (void)setY:(CGFloat)y { CGRect frame = self.frame; frame.origin.y = y; self.frame = frame; } - (CGFloat)y { return self.frame.origin.y; } - (void)setCenterX:(CGFloat)centerX { CGPoint center = self.center; center.x = centerX; self.center = center; } - (CGFloat)centerX { return self.center.x; } - (void)setCenterY:(CGFloat)centerY { CGPoint center = self.center; center.y = centerY; self.center = center; } - (CGFloat)centerY { return self.center.y; } - (void)setWidth:(CGFloat)width { CGRect frame = self.frame; frame.size.width = width; self.frame = frame; } - (CGFloat)width { return self.frame.size.width; } - (void)setHeight:(CGFloat)height { CGRect frame = self.frame; frame.size.height = height; self.frame = frame; } - (CGFloat)height { return self.frame.size.height; } - (void)setSize:(CGSize)size { // self.width = size.width; // self.height = size.height; CGRect frame = self.frame; frame.size = size; self.frame = frame; } - (CGSize)size { return self.frame.size; } @end
三:思路分析:ui
1:先添加首頁,信息,發現,我四個控制器爲根視圖控制器的子控制器,在viewDidload方法裏封裝方法[self addAllChildVcs];調用。由於四個子控制器中每一個子控制器都要設置title,Vc.tabBarItem.image,Vc.abBarItem.selectedImage,以及abBarItem的文字屬性,還要包裝一層導航控制器,最後addChildViewController做爲根視圖控制器的子控制器。此時會有大量重複的代碼,因此要想抽取代碼的思想,將大量重複的代碼抽成一個方法,把相同的代碼封裝在方法的內部,不一樣的部分做爲參數傳遞。因此將此段代碼抽成一個方法:- (void)addOneChlildVc:(UIViewController *)childVc title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName;建立出子控制器對象後,將子控制器對象,title,image ,selectedImage做爲參數傳遞。atom
2:設置tabItem的文字屬性:1:在封裝方法中,設置標題屬性, childVc.title = title;此句代碼既設置了tabBaritem上的標題,也設置了相應子控制器的導航欄的標題。設置tabBar上不一樣狀態下的標題的文字屬性:利用方法 setTitleTextAttributes:dic forState:state 就能夠設置不一樣狀態下的文字屬性,常態,高亮,失效。(給字典賦值:dic[key]= value;dic爲可變字典)
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10];
[childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
3:設置tabItem上不一樣狀態下的圖片屬性:1:Normal :childVc.tabBarItem.image = [UIImage imageWithName:imageName]; 2:selected: UIImage *selectedImage = [UIImage imageWithName:selectedImageName];
if (iOS7) {
// 聲明這張圖片用原圖(別渲染) selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; }
childVc.tabBarItem.selectedImage = selectedImage;
注意:1:判斷是不是ios7,能夠在pch文件中作宏定義,其中一些宏定義,一些頭文件均可以在pch中作定義。
#define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue] >= 7.0)
2:對於NSLog的宏定義也能夠在pch中:
1 #ifdef DEBUG //調式狀態 2 #define DLog(...) NSLog (__VA_ARGS__) 3 #else //發佈狀態 4 #define DLog (...) 5 #endif
3:單例的宏定義:
//單例的宏定義:斜線向右,表示下一行也屬於宏定義 #define Single_interface(className) +(className*)shared##className #define Single_implemtation(className) +(className*)shared##className { \ \ static className *instance = nil;\ static dispatch_once_t onceToken;\ dispatch_once(&onceToken, ^{\ \ instance = [[self alloc]init];\ });\ \ return instance;\ }
4:在系統大於或等於ios7時,系統默認會對系統的一些控件產生渲染,渲染爲藍色,例如button爲系統樣式時,會被渲染爲藍色,而tabBarItem上的圖片,normal狀態下不會被渲染,只有是選中selected狀態下才會被渲染成藍色。解決辦法:三部曲:1:先建立圖片 2:判斷是否爲ios7如果則調用UIImage的方法imageWithRenderingMode,告訴系統不要渲染,保持原圖,並返回一張原圖的圖片。selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 3:設置tabBarietm上的選中圖片
UIImage *selectedImage = [UIImage imageWithName:selectedImageName]; if (iOS7) { // 聲明這張圖片用原圖(別渲染) selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } childVc.tabBarItem.selectedImage = selectedImage;
5:給每個子控制器包裝一層導航控制,主要自定義導航控制器,爲了設置導航控制器上item的屬性。新建類繼承UINavigationController。1:由於只要是自定義了導航控制器,則系統的側滑返回效果就會消失,只要在viewDidLoad裏將手勢代理清空便可:self.interactivePopGestureRecognizer.delegate = nil;
2:自定義UINavigationBar 和 UIBarButtonItem:1:其中UINavigationBar爲整個導航欄,設置其主體主要設置的是導航欄的背景色,背景圖片,title文字的屬性。UIBarButtonItem:設置的是導航欄上左右按鈕的圖片或是文字屬性。3:UINavigationBar *appearance = [UINavigationBar appearance];UIBarButtonItem *appearance = [UIBarButtonItem appearance];經過appearance方法返回的兩個對象是全局對象,經過設置這兩個對象的屬性,就能夠達到整個項目中全局設置,由於在整個項目中只須要設置一次,因此不須要在ViewDidload裏去設置,由於沒建立一次對象,ViewDidload就會調用一次,這樣導航欄的主題就會被重複設置,因此將設置導航欄主題的方法封裝在,+ (void)initialize,該方法只會在該類第一次使用,也就是該類的第一個方法被調用以前調用,有且只調用一次。在內部封裝的方法應爲類方法,用self去調用,在類方法中self指向的是當前的類,在對象方法中self指向的是當前的對象。
3:設置UINavigationBar屬性:得到全局導航欄對象appearance,1:能夠設置其背景色tintColor ,2:背景圖片:setBackgroundImage forBarMetrics: 第二個參數爲默認便可 2:設置title的文字屬性: [appearance setTitleTextAttributes:textAttrs];不用設置狀態。(在開發中有些方法是過時會有警告,其實也能用,只不過是有新的方法能夠代替它),設置title字體的偏移量也就是陰影效果,textAttrs[NSShadowAttributeName] = [NSValue valueWithUIOffset:UIOffsetZero];其中CGRect,CGPoint,UIOffset 都是結構體,只有封裝成NSValue對象,才能夠放到數組或是字典中。
4:設置UIBarButtonItem的主題:1:UIBarButtonItem也就是導航欄上的左右按鈕,能夠利用setTitleTextAttributes
forState 屬性分別設置左右按鈕的常態,高亮,失效狀態下的文字屬性。2:當左右按鈕爲一張圖片時,給UIBarButtonItem寫一個分類,設置customView自定義按鈕,直接設置按鈕的背景圖片爲該張圖片就能夠。
5:重寫導航控制器的push方法:1:目的是攔截push方法,由於每一個棧裏的控制器,左右按鈕都相同,因此不須要再棧裏每一個控制器裏建立左右按鈕。攔截導航控制器的push方法,當壓棧的時候,就爲每一個即將壓棧的控制器設置了左右按鈕。2:在將四個主控制器包裝導航控制器的時候,initWithrootViewController,已經把該四個控制器壓入棧裏,此時會調用導航控制器的push方法,
/** * 能攔截全部push進來的子控制器 */ - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { if (self.viewControllers.count > 0) { // 若是如今push的不是棧底控制器(最早push進來的那個控制器) viewController.hidesBottomBarWhenPushed = YES; // 設置導航欄按鈕 viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_back" highImageName:@"navigationbar_back_highlighted" target:self action:@selector(back)]; viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImageName:@"navigationbar_more" highImageName:@"navigationbar_more_highlighted" target:self action:@selector(more)]; } [super pushViewController:viewController animated:animated]; }
1:重寫的push方法,1:傳入的viewController爲即將壓棧的控制器,重寫系統的方法,不要忘記調用super。super方法在左後調用,是避免爲四個主控制器也設置左右按鈕 2:拿到導航控制器棧裏的子控制器數組:nav.viewControllers(self.viewControllers),判斷子控制器數組裏的控制器個數 > 0,則表示不是棧底控制器。此時能夠拿到即將壓棧的控制器設置左右item:viewController.navigationItem.leftBarButtonItem。2:對左右按鈕爲圖片的直接將圖片設置爲btn的背景圖片,給UIBarButtonItem寫一個分類,傳入normalImage ,HighlightedImage,target,action,自定義btn,設置不一樣狀態下的背景圖片,通常對於圖片按鈕來講,按鈕的大小就設置爲圖片的大小。對於button來講,得到當前的image,title,backgroundImage的方法,btn.currentTtitle,btn.currentImage,btn.currentBackgroundImage 3:若想調整左右按鈕距離屏幕的左右間距:能夠自定navbar繼承系統的bar,重寫layoutSubView方法,遍歷子控件數組,分別找到左右按鈕,調整左右按鈕的frame。再利用kvc的setValue forKeyPath,來替換掉系統的navBar(只需建立自定義bar的對象,由於繼承於系統,因此係統所聲明的非私有的屬性方法變量都會繼承,不用設置frame,第一個參數爲建立的自定義navbar對象,第二個參數爲導航控制器或是tabbar控制器下的navbar,或是tabbar以屬性定義的對象) 4:當push壓棧的時候,須要隱藏tabBar,此時可在攔截的push方法中,拿到即將壓棧的控制器,調用
//0:當push的時候隱藏dock欄 viewController.hidesBottomBarWhenPushed = YES;
2:自定義tabBar的封裝:1:+(instancetype)tabBar;return [self alloc ]init]; 類方法快速返回一個對象,alloc內部會調用alloc initWithFrame方法,因此重寫alloc initWithFrame方法,在此方法內先設置自身的屬性:能夠設置tabbar的背景圖片self.backgroundImage 或是選中的背景圖片,self.selectionIndicatorImage = [UIImage imageWithName:@"navigationbar_button_background"];2:懶加載子控件,設置控件的屬性,將控件添加到父視圖上。建立中間的加號按鈕,常態,高亮狀態下的背景圖片,setImage設置常態高亮狀態下的圖片,添加監聽,添加到父視圖上。3:在layoutSubView裏設置控件的frame,(若爲圖片按鈕,有不一樣狀態,就設圖片爲整個按鈕背景,分貝設常態,高亮,選中狀態下的背景圖片,按鈕的大小爲圖片的大小:btn.currentTitle,btn.currentImage,btn.currentBackgroundImage便可得到當前顯示的圖片和標題。)如何拿到控件設置frame,1:屬性,成員變量,枚舉tag值 2:大數組思想:裝在大數組,當一個控件上分別有不一樣的控件的時候,能夠兩兩分別裝在數組裏,用到的時候再從數組裏取出 3:繼承UIView的能夠遍歷self.subViews,遍歷子控件的數組,作條件過濾,找到中止遍歷。如果UIScrollView,會多出兩個控件橫豎滾動條,直接隱藏就不會顯示了,隱藏後可直接遍歷子控件數組,也能夠提早給View設置tag值,當遍歷時,找到父view後,經過tag值將view取出 。當父view上有多個控件時,還能夠遍歷子控件數組,作過濾,當找到須要設置frame的控件後,須要根據index設置frame,此時在循環中沒法拿到index,就本身定義一個index,找到控件後執行index++,根據控件的索引來設置frame 4:設置按鈕的tag值:1:直接設置(可爲0)2:枚舉tag值,用於按鈕的回調,根據枚舉值判斷是哪一個按鈕 3:btn.tag =self.subViews.count,適用於將按鈕取出,或是應用於本類中 。4:因此設置加號按鈕的size爲圖片的size,經過btn.currentBackgroundImage把圖片取出(通常給系統控件賦值時,調用的是系統控件的set方法,若想在其餘地方得到該值,能夠調用其系統控件的get方法,例如btn的三個方法,lable.font,vc.title等),若是控件須要居中顯示的話,就設置控件的center屬性,例如新特性界面的pageControl的frame設置方法。5:雖然是自定義的tabBar,可是繼承的是系統的tabBar,已經添加了四個子控制器,因此自定義的tabbar上已經添加了四個按鈕。須要從新調整四個按鈕的距離。在layoutSubView裏從新調整四個按鈕的frame。遍歷子控件數組,作條件過濾,並打印,有的是系統沒有聲明的屬性,打印出只是一個字符串,利用NSSClassFromString();方法將字符串轉化爲類來判斷是否屬於.
/** * 設置全部tabbarButton的frame */ - (void)setupAllTabBarButtonsFrame { int index = 0; // 遍歷全部的button for (UIView *tabBarButton in self.subviews) { // 若是不是UITabBarButton, 直接跳過 if (![tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) continue; // 根據索引調整位置 [self setupTabBarButtonFrame:tabBarButton atIndex:index]; // 索引增長 index++; } } /** * 設置某個按鈕的frame * * @param tabBarButton 須要設置的按鈕 * @param index 按鈕所在的索引 */ - (void)setupTabBarButtonFrame:(UIView *)tabBarButton atIndex:(int)index { // 計算button的尺寸 CGFloat buttonW = self.width / (self.items.count + 1); CGFloat buttonH = self.height; tabBarButton.width = buttonW; tabBarButton.height = buttonH; if (index >= 2) { tabBarButton.x = buttonW * (index + 1); } else { tabBarButton.x = buttonW * index; } tabBarButton.y = 0; } @end
設置frame的思路:1:tabBar上已經添加上了5個按鈕,就讓這5個按鈕評分tabBar的寬度,注意:self.ietms.count,雖然此時tabBar已經有5個按鈕了,可是個數爲4,它指的是加入tabBarcontroller中的子控制器的個數。高度爲自身tabBar的高度,y值爲0,x值的設置,前兩個能夠根據索引正常設置buttonW * index,到後兩個的時候:buttonW * (index + 1)。2:當在layoutSubView裏設置frame時,遍歷取出控件,根據index設置frame,若是沒法遍歷,能夠本身構造index,實現index++,將index傳過去。
5:tabBar點擊中間加號按鈕的回調:1:回調可用協議代理,block ,通知,前兩個用於層級較淺的回調,通知適用於層級較深的回調 2:其中兩個控制器須要回調數據時,若兩個控制器須要實時相互回調數據,可用block和協議代理,設置返回值,當一端回調數據後,處理完數據後,還能夠返回一些給原控制器提供回調數據。3:協議代理的方法默認爲@require,注意協議代書寫的規範性,仿照tableView的代理來設置
6:在tabBarController裏利用kvc替換系統的tabBar:不用設置frame
/** * 建立自定義tabbar */ - (void)addCustomTabBar { // 建立自定義tabbar HMTabBar *customTabBar = [[HMTabBar alloc] init]; customTabBar.tabBarDelegate = self; // 更換系統自帶的tabbar [self setValue:customTabBar forKeyPath:@"tabBar"]; }
7:UIImage的封裝:分類封裝
#import <UIKit/UIKit.h> @interface UIImage (Extension) /** * 根據圖片名自動加載適配iOS6\7的圖片 */ + (UIImage *)imageWithName:(NSString *)name; /** * 根據圖片名返回一張可以自由拉伸的圖片 */ + (UIImage *)resizedImage:(NSString *)name; @end
#import "UIImage+Extension.h" @implementation UIImage (Extension) + (UIImage *)imageWithName:(NSString *)name { UIImage *image = nil; if (iOS7) { // 處理iOS7的狀況 NSString *newName = [name stringByAppendingString:@"_os7"]; image = [UIImage imageNamed:newName]; } if (image == nil) { image = [UIImage imageNamed:name]; } return image; } + (UIImage *)resizedImage:(NSString *)name { UIImage *image = [UIImage imageWithName:name]; return [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5]; } @end
賦值代碼的三部曲:1:外部先定義一個變量 2:中間根據判斷條件拿到變量賦值 3:從新給變量賦值(若判斷條件不符合,則變量的值沒有改變,如果符合,則發生了改變)