百思不得姐框架(二)


一 該部分框架效果圖和實現思路

框架二的效果圖:

框架效果圖

實現思路:

—- 1> 先完善tabBar(主要是自定義)
—- 2> 再完善導航條
—- 3> 其次完善屏幕側滑(主要是全屏側滑功能)

二 抽取分類(設置到插件中)

1 抽取分類的思想: 實現復用

—-> 1.1 上部分代碼中,我們需要設置tabBar中圖片成未被渲染的格式,因此我們抽取了一個分類,用分類里面的方法實現了效果.
—-> 分類代碼:
//傳入一張圖片的名稱返回一張未被渲染的圖片
+ (UIImage *)originalWithImage:(NSString *)imageName
{
UIImage *image = [UIImage imageNamed:imageName];

return [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}

2 問題:雖然抽取了分類,但是我們是不是想在用分類設置圖片的時候,也能有插件提示功能呢?

設置插件功能圖:(圖一)

這里寫圖片描述

具體的設置思路:<—>見下圖

2.1 按住option,點擊桌面的左上角,找到前往,點擊資源庫
圖一:

這里寫圖片描述

圖二:

這里寫圖片描述

圖三:

這里寫圖片描述

圖四:

這里寫圖片描述

圖五:

這里寫圖片描述

圖六:

這里寫圖片描述

圖七:

這里寫圖片描述

最后:找到插件的位置,具體做法就是先command + c 然后command + v 賦值個item,然后將圖七中的改為自己的分類方法就可以.

三 問題一

1 問題: 選中的圖片中,配圖的文字被渲染了(圖片不被渲染我們用分類解決了)
2 實現思路:
—-> 1> 通過獲取到全局的tabBar
—-> 2> 再通過字典來包裝設置字體顏色和字體的大小
3 在自定義的tabBarController控制器中設置選中字體的顏色不被渲染(全程序只需要設置一次)–>選中狀態
4 通過拿到全局的tabBarItem去設置按鈕的字體大小(由整個app的效果圖知道,字體需要加粗)

具體代碼:

#pragma mark - 設置標題的字體不被渲染(該方法全程序只會來一次)
+ (void)load
{
//獲取全局的tabBar
UITabBarItem *tabBar = [UITabBarItem appearance];
//創建可變字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//設置文字的顏色
dict[NSegroundColorAttributeName] = [UIColor blackColor];
//設置字體
[tabBar setTitleTextAttributes:dict forState:UIControlStateSelected];
NSMutableDictionary *dict1 = [NSMutableDictionary dictionary];
//設置文字的大小
dict1[NSFontAttributeName] = [UIFont boldSystemFontOfSize:13];
//設置字體大小
[tabBar setTitleTextAttributes:dict1 forState:UIControlStateNormal];
}
5 發布按鈕顯示不出來—>發布按鈕的圖片比較大,顯示出來就會有問題
—-> 5.1 讓正常狀態下的圖片也不被渲染(能達到效果)
nav2.tabBarItem.image = [UIImage originalWithImage:@"tabBar_publish_icon"];
—-> 5.2 設置對應的控制器的tabBarItem,通過設置圖片的內邊距來實現(通過測試也不符合條件:原因是選中時候高亮,但是不選中的時候就會恢復狀態)–>很明顯是高亮狀態
publish.tabBarItem.imageInsets = UIEdgeInsetsMake(7, 0, -7, 0);

四 自定義tabBar

1 為了解決tabBar的問題,我們自定義tabBar(繼承系統的UITabBar)

見圖:

這里寫圖片描述

2 修改tabBar內部子控件位置

3 把系統的tabBar替換為自己的tabBar(只需要創建一次)–(KVC)

具體實現代碼:
#pragma mark - 運用自定義的tabBar
- (void)setUpTabBar
{
//創建自定義tabBar
XFJTabBar *tabBar = [[XFJTabBar alloc] init];
//KVC賦值
[self setValue:tabBar forKey:@"tabBar"];
}

4 重寫layoutSubViews(布局tabBar中的子控件)

4.1 調整內部子控件的位置(遍歷所有的子控件,然后判斷子控件的類型,將中間的按鈕位置空出來)

注意部分: 通過打印tabBar的子控件的類型,我們知道了按鈕的類型是—> UITabBarButton這種類型的

代碼詳見:
#pragma mark - 布局子控件
- (void)layoutSubviews
{
[super layoutSubviews];
//獲取子控件的總數
NSInteger count = self.items.count + 1;
//設置按鈕的尺寸的屬性
CGFloat buttonX = 0;
CGFloat buttonY = 0;
CGFloat buttonW = self.XFJ_Width / count;
CGFloat buttonH = self.XFJ_height;
NSInteger i= 0;
//遍歷
for (UIView *button in self.subviews) {
//判斷為該種類型的時候才進行下面
if ([button isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
if (i == 2) {
i = i + 1;
}
//按鈕的X值
buttonX = i * buttonW;
//按鈕的尺寸
button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
i ++;
}
}
//設置發布按鈕的餓擺放位置
self.plusButton.center = CGPointMake(self.XFJ_Width * 0.5, self.XFJ_height * 0.5);
}
4.2 懶加載(通過懶加載創建發布按鈕,然后在內部設置屬性)—>由於只需要創建一次,所以用懶加載實現
#pragma mark - 懶加載
- (UIButton *)plusButton
{
if (_plusButton == nil) {
//創建按鈕
UIButton *plusButton = [UIButton buttonWithType:UIButtonTypeCustom];
//設置按鈕的圖片(平常狀態)
[plusButton setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal];
//高亮狀態
[plusButton setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted];
//賦值
self.plusButton = plusButton;
//自適應
[plusButton sizeToFit];

[self addSubview:plusButton];
}
return _plusButton;
}

五 問題二

問題: 我們很多時候需要在外界直接修改控件的尺寸,但是傳統的寫法太麻煩.

解決辦法:創建分類,在外界直接修改X,Y,width,Height的時候,能直接點出來

代碼塊一 :
@property CGFloat XFJ_x;
@property CGFloat XFJ_y;
@property CGFloat XFJ_Width;
@property CGFloat XFJ_height;
代碼塊二(在分類的內部實現了尺寸的修改,外面直接就可以點出來用):
- (void)setXFJ_x:(CGFloat)XFJ_x
{
CGRect frame = self.frame;
frame.origin.x = XFJ_x;
self.frame = frame;
}

- (CGFloat)XFJ_x
{
return self.frame.origin.x;
}

六 PCH文件

1 創建一個PCH文件(注意命名方式:和工程名一樣),將全程序都需要的用到的文件都放到里面–>prefix

—-> PCH文件的實現思路:將pch文件中的代碼,全部都拷貝一個到每個文件中,然后編譯.

2 具體PCH配置:

詳見圖一:

這里寫圖片描述

詳見圖二:(注意文件的路徑)

這里寫圖片描述

七 精華模塊導航條的內容

1 導航條左邊的按鈕圖片(封裝一個分類)—->封裝原因:我們想直接通過傳入兩張圖,直接返回一個設置好的UIBarButtonItem對象.

—-> 寫在分類中的代碼:
+ (UIBarButtonItem *)itemWithImage:(UIImage *)image heightImage:(UIImage *)heighImage target:(id)target action:(SEL)action
{
//創建按鈕
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
//設置按鈕圖片
[button setImage:image forState:UIControlStateNormal];
//高亮狀態
[button setImage:heighImage forState:UIControlStateHighlighted];
//設置按鈕的尺寸
[button sizeToFit];
//按鈕的點擊事件
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
//返回一個設置好的按鈕
return [[UIBarButtonItem alloc ]initWithCustomView:button];
}
—-> 設置左邊圖片:
- (void)setUpNavBar
{
//左邊的樣式
UIBarButtonItem *item = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"nav_item_game_icon"] heightImage:[UIImage imageNamed:@"nav_item_game_click_icon"] target:self action:@selector(game)];
—-> 設置右邊的圖片:
//右邊的樣式
UIBarButtonItem *item1 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"navigationButtonRandom"] heightImage:[UIImage imageNamed:@"navigationButtonRandomClick"] target:self action:@selector(task)];

self.navigationItem.rightBarButtonItem = item1;
—-> 設置標題(注意:導航條的標題是一張圖片)
#pragma mark - 設置導航條標題
- (void)setUpNavTitle
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MainTitle"]];
self.navigationItem.titleView = imageView;
}

2 是不是所有的類都能拿到全局的外觀?

解答: 不是,只有遵守了UIAppearance協議就可以通過appearance獲取全局外觀.

3 設置全局導航條的背景圖片和顯示的字體

具體代碼:
//獲取全局的導航條
UINavigationBar *navBar = [UINavigationBar appearance];
//設置背景圖片
[navBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
//設置字體
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSFontAttributeName] = [UIFont boldSystemFontOfSize:20];
[navBar setTitleTextAttributes:dict];

八 bug

ios8會出現的bug:把短信界面導航條改了,聯系人界面會出現黑的.

九 跳轉設置

1 自定義設置控制器(UITableViewController)

這里寫圖片描述

2 控制器”我”導航條右側的圖片

#pragma mark - 添加控制器我的右邊的圖片
- (void)setImageWithRight
{
//控制器右邊的圖片
UIBarButtonItem *item1 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"mine-moon-icon"] heightImage:[UIImage imageNamed:@"mine-moon-icon-click"] target:self action:@selector(moon)];
UIBarButtonItem *item2 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"mine-setting-icon"] heightImage:[UIImage imageNamed:@"mine-setting-icon-click"] target:self action:@selector(setting)];
//設置右邊的圖片
self.navigationItem.rightBarButtonItems = @[item2,item1];
}

3 跳轉到設置界面

#pragma mark - 點擊事件的實現(setting)
- (void)setting
{
NSLog(@"setting");

//創建跳轉控制器
XFJSettingViewController *setting = [[XFJSettingViewController alloc] init];

//在push之前隱藏底部的tabBar
setting.hidesBottomBarWhenPushed = YES;

//跳轉控制器
[self.navigationController pushViewController:setting animated:YES];
}

4 跳轉后出現的問題:

—-> 4.1 底部條沒有隱藏
//在push之前隱藏底部的tabBar
setting.hidesBottomBarWhenPushed = YES;
—-> 4.2 返回按鈕樣式(一定要在有內容的前提下,才能設置內邊距)

5 設置全局返回按鈕(重寫push方法)

#pragma mark - 重寫push方法
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
NSLog(@"%@",self.interactivePopGestureRecognizer);
//判斷,只有是分根控制器才能返回
if (self.childViewControllers.count > 0) {
//創建按鈕
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
//設置按鈕沒有點擊的圖片
[button setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
//設置按鈕點擊后的圖片
[button setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];
//設置返回按鈕字樣
[button setTitle:@"返回" forState:UIControlStateNormal];
//設置返回按鈕的標題的正常樣式
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//設置返回按鈕的標題的點擊樣式
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
//設置按鈕的尺寸
[button sizeToFit];
//設置按鈕的監聽方法
[button addTarget:self action:@selector(backBtn) forControlEvents:UIControlEventTouchUpInside];
//設置返回按鈕與左邊的距離
button.contentEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
//添加按鈕
viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
}
[super pushViewController:viewController animated:animated];
}

十 重寫push方法出現的bug—>系統的滑動返回功能失效了

1 解決辦法: 清空代理—->會出現bug(假死狀態:程序一直在跑,但是界面死了)
2 假死原因:在根控制器下,滑動返回,不應該在根控制器的view上滑動返回
3 解決辦法:把自己設置為手勢的代理,實現代理方法,判斷,如果是根控制器,讓手勢沒有效果(是否觸發手勢的代理方法)

代碼塊一:

self.interactivePopGestureRecognizer.delegate = self;

代碼塊二:

#pragma mark - 代理方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//只有當導航控制器的子控制器的數量大於1的時候,才能側滑
return self.childViewControllers.count > 1;
}

十一 全屏滑動

1 分析:為什么導航控制器的滑動手勢只能邊緣滑動?

2 通過打印出代理的類型和action的方法,我們可以添加一個全屏滑動的功能,但是需要設置手勢的代理,否則在根控制器的時候,又會出現假死的狀態.

—->打印出系統側滑功能的代理(紅色部分是代理需要調用的方法)
<UIScreenEdgePanGestureRecognizer: 0x7fe5b2493980; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7fe5b24920d0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fe5b2493860>)>>
—-> 代碼塊一:
#pragma mark - 添加全屏側滑功能
- (void)setWithScreenPan
{
//創建手勢
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
//添加手勢
[self.view addGestureRecognizer:pan];

//設置代理為自己
pan.delegate = self;
}
代碼塊二:
//添加手勢
[self setWithScreenPan];

//清空代理,但是必須是在添加手勢之后
self.interactivePopGestureRecognizer.enabled = NO;

十二 總結

1 該部分是有關tabBar和導航條的設置,里面涉及到自定義.設置好了系統的返回功能,但是由於重寫而產生的一系列問題.里面已經涉及到了所有情況的解決思路,可能有一些不是很完整.后期我將一一解決.

2 今天只是框架二 ,明天我將為大家講解后面的部分,大家有什么問題,麻煩留言,謝謝!!!!


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com