知识点总结:03-按钮的设置和导航控制器pop手势

0.OC中两种获取类的方式

D2380F74-785F-4FF7-A062-FAEF550BC7D1.png

1.控制台可能会输出以下警告信息

  • 警告的原因: [UIImage imageNamed:nil]
// 没有输入图片名
CUICatalog: Invalid asset name supplied: (null)
CUICatalog: Invalid asset name supplied: (null)
  • 警告的原因: [UIImage imageNamed:@""]
// 图片名是空
CUICatalog: Invalid asset name supplied:
CUICatalog: Invalid asset name supplied:

2.准确判断一个字符串是否有内容

if (string.length) {
  // doSomething
}

/*
错误写法:
if (string) {
    // 这相当于判断string是否为nil,但是忽略了string为""的情况
}

// -> 如果是数组,则是array.count
*/
  • 判断传入的图片名不是nil且不是@"", 再予以赋值image
C1C6F8D5-A982-48DE-A483-259DB275947A.png

4.center和size的设置顺序

  • 建议的设置顺序


    07FE1049-AFA7-47B4-A0A9-4E7CAA528418.png
    • 先设置size(改变大小,通过bounds或者frame设置,会改变origin)
    • 再设置center (改变origin,不管size是不是通过bounds或者frame设置,设置center以后都会被重新设置origin)

    如果上面的顺序调换过来,会出现错误,中心点会定位到屏幕中心,origin为(self.view.frame.size.wide / 2, self.view.frame.size.height / 2),然后不改变origin的情况下,设置size,这时这个矩形会处于右下方,因此它们的次序不同结果是不同的.

5.给系统的自带的类增加分类(以UIView为例,用OC文件创建分类,如果是写单例Manager则创建自定义类继承NSObject)

C3F422E2-3CD2-48DF-82CE-457C01538731.png
  • 建议增加的分类属性名\方法名前面加上前缀, 比如
@interface UIView (XMGExtension)
@property (nonatomic, assign) CGFloat zgk_width;
@property (nonatomic, assign) CGFloat zgk_height;
@property (nonatomic, assign) CGFloat zgk_x;
@property (nonatomic, assign) CGFloat zgk_y;
@property (nonatomic, assign) CGFloat zgk_centerX;
@property (nonatomic, assign) CGFloat zgk_centerY;
@property (nonatomic, assign) CGFloat zgk_right;
@property (nonatomic, assign) CGFloat zgk_bottom;
@end

- 这样做的好处有两个:
         1.跟系统的属性区分开来,例如避免苹果为UIView添加相同名字的属性
         2.看就知道这个是自己写的分类

6.按钮常见的访问方法

  • 设置按钮的图片和文字是要分状态的, 如: [backButton setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];

错误示范:(不知道image是赋值给什么状态下的btn)


A08EA744-192F-4871-A8BC-410071733C4E.png

正确示范:

/** navigationController中设置返回按钮 **/
 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.childViewControllers.count > 0) { // 如果viewController不是最早push进来的子控制器
        // 左上角
        UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];
        [backButton setTitle:@"返回" forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
        [backButton sizeToFit];
        // 这句代码放在sizeToFit后面
        backButton.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
        [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
        
        // 隐藏底部的工具条
        viewController.hidesBottomBarWhenPushed = YES;
    }
    
    // 所有设置搞定后, 再push控制器
    [super pushViewController:viewController animated:animated];
}
// 获取btn正常状态下的图片
[button imageForState:UIControlStateNormal].size;
button.currentImage.size;

// 获取btn正常状态下的背景图片
[button backgroundImageForState:UIControlStateNormal];
button.currentBackgroundImage;

// 获取btn正常状态下的文字
[button titleForState:UIControlStateNormal];
button.currentTitle;

// 获取btn正常状态下的文字颜色
[button titleColorForState:UIControlStateNormal];
button.currentTitleColor;

7.为什么要设置navgationController作为tabBarController的子控制器呢?因为要要设置导航栏标题,所以要在每个子控制器中设置navgationItem.title属性

991274FE-A7E9-4E91-8E6E-DB793D17164C.png

从上述结构转变为下面结构:

F72FEF2F-4E2A-4DD4-A89F-BA5923F0167F.png
C3231499-E84A-42BD-8996-8F80AD9EC421.png

从上述代码转变为下面代码:


F6CF4694-7A8B-4421-BD05-E605EDC11D8C.png
  • 需要说明一下的是:tabBarController一般是用于同级界面的跳转,而navigationController一般是用于某个控制器中与子控制器之间的跳转.

  • navigationBar的内容是栈顶控制器的navigationItem决定的,tabbarBar的内容是其子控制器的tabBaritem决定的

E080E072-87DA-4113-8088-843F6F12E786.png
 /**** tabBarController.tabBar通过添加子控制器,来设置tabBar导航栏的内容 ****/

    /**在UITabBarController中**/
    [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"精华" image:@"tabBar_essence_icon" selectedImage:@"tabBar_essence_click_icon"];

- (void)setupOneChildViewController:(UIViewController *)vc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage
{
    vc.view.backgroundColor = XMGRandomColor;
    vc.tabBarItem.title = title;
    if (image.length) { // 图片名有具体值
        vc.tabBarItem.image = [UIImage imageNamed:image];
        vc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImage];
    }
    // tabBarController.tabBar通过添加子控制器,来设置tabBar的内容 
    [self addChildViewController:vc];
}
/** navigationController的栈顶控制器中设置导航栏内容 **/ 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = XMGCommonBgColor;
    
    // 标题
    self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MainTitle"]];
    // 左边
    self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImage:@"MainTagSubIcon" highImage:@"MainTagSubIconClick" target:self action:@selector(tagClick)];
}

8.设置按钮的内边距

  • btn中有两个控件,一个是imageView,一个是label,重写btn可以设置它们的frame,一般是图片在左,文字在右.
// btn中内容的内边距(包括图片和文字)
@property(nonatomic) UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR;
// btn中文字的内边距
@property(nonatomic) UIEdgeInsets titleEdgeInsets;
// btn中图片的内边距
@property(nonatomic) UIEdgeInsets imageEdgeInsets;

9.不建议用self.title来修改navigationBar导航栏的标题,因为它会同时修改其他tabBarbar中的按钮标题

10.设置返回按钮的两种方法

  • 第一种方法
17F4967C-4872-42C5-BAED-F9FB6268C6A8.png
  • 第二种方法
EEB6BBC2-16F8-44BC-8776-15B8CF83EC85.png

第二种方法将按钮数组直接穿进去,不用设置frame,推荐使用.

11.因为返回按钮经常用到,如果要统一设置自定义返回按钮(如果不自定义返回按钮,则返回的按钮会显示上个控制器的标题,而不是"返回"字眼),有两种方法:自定义类和分类

  • 自定义类:继承NSObject,抽取一个类来专门管理返回btn
51F11E81-600D-4587-9E5C-1D284A6E33DA.png
B18AA519-7645-4968-A10D-00579C4EEB5E.png
  • 分类:创建OC文件,给btn添加分类(instancetype返回的是自己)


    356CF41A-E897-48B9-BD4C-C73070D9CF87.png

    分类不用创建新的类,简单明了,推荐使用分类

设置左边返回按钮需要注意的方面

B0B543E0-FB9F-4B99-A214-9C9E51CA5057.png
注意点:
1.设置返回按钮的不是简单的"返回",而是"箭头+返回",因此要设置image和title属性,并且要分状态
2.如果要设置图片不在左边在上面,文字在下面,则要自定义按钮 
3.设置按钮的内边距,可以调节返回按钮的布局,距离左边近一点,有图片内边距,有文字内边距,有内容内边距,用内容内边距 
4.在当前控制器设置,导航条的返回按钮
5.设置内边距的代码要放在sizeTofit之后,在根据内容确定大小后,再设置内边距,达到美观的效果.

12.自定义navigationViewController来统一设置返回按钮,这样就不用在每个navigationViewContrller的子控制器中设置返回按钮

/**
 *  重写push方法的目的 : 拦截所有push进来的子控制器
 *
 *  @param viewController 刚刚push进来的子控制器
 */
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.childViewControllers.count > 0) { // 如果viewController不是最早push进来的子控制器
        // 左上角
        UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
        [backButton setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];
        [backButton setTitle:@"返回" forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [backButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
        [backButton sizeToFit];
        // 这句代码放在sizeToFit后面
        backButton.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
        [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
        
        // 隐藏底部的工具条
        viewController.hidesBottomBarWhenPushed = YES;
    }
    
    // 所有设置搞定后, 再push控制器
    [super pushViewController:viewController animated:animated];
}

13.解决导航控制器pop手势失效(自定义导航控制器)

#import "ZGKNavigationController.h"

- (void)viewDidLoad {
    [super viewDidLoad];    
    self.interactivePopGestureRecognizer.delegate = self;
    
    [self.navigationBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
}

#pragma mark - <UIGestureRecognizerDelegate>
/**
 *  手势识别器对象会调用这个代理方法来决定手势是否有效
 *
 *  @return YES : 手势有效, NO : 手势无效
 */
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//    if (self.childViewControllers.count == 1) { // 导航控制器中只有1个子控制器
//        return NO;
//    }
//    return YES;
    
    // 手势何时有效 : 当导航控制器的子控制器个数 > 1就有效
    return self.childViewControllers.count > 1;
}

14.为什么要设置navigationBar和tabBar的背景颜色

  • navigaitonBar的背景颜色默认是半透明的,如果栈顶控制器的背景颜色是黑色的话,在跳转的时候会有黑影,所以要设置
/** 自定义navigationViewController中的代码 **/
 @implementation XMGNavigationController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.interactivePopGestureRecognizer.delegate = self;
    [self.navigationBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
}
  • tabBar也是因为出现影子的情况,所以最好也是自己设置背景图片
/** 自定义tabBar中的代码 **/
#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        self.backgroundImage = [UIImage imageNamed:@"tabbar-light"];
    }
    return self;
}

15.其他需要注意的

6BD9F0C4-D9D5-4006-B9F4-8677477A3070.png
  • 划分类的时候,我们可以通过所选文件创建文件夹,这时要修改pch的路径,直接拖入然后删掉前面设置的地址即可

  • tabBarViewController的子控制器都是懒加载的,所以不要在tabBarViewController中随便设置子控制器的的background,直接在子控制器的viewDidLoad方法中设置即可

  • sizeTofit是根据内容的大小,确定大小,一般设置sizeToFit之后再调整内边距达到美观的效果

@property(nonatomic) UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR;
@property(nonatomic) UIEdgeInsets titleEdgeInsets;
@property(nonatomic) UIEdgeInsets imageEdgeInsets;
  • 图片是有缓存的,多次创建同一个图片不会消耗性能

  • 如果上一个控制器设置了vc.hidesBottomBarWhenPushed = YES,那么push出来的另外一个控制器就不用再设置hidesBottomBarWhenPushed

  • 在一个控制器统一设置外观可以用appearance,在多个控制器设置外观可以通过继承来实现功能(或者自定义类,分类),如:1. tabBarViewController用appearance统一设置tabBarButton的图片和文字格式; 2.多个控制器通过继承控制器实现设置相同的返回按钮

  • 继承的弊端:继承以后,你所创建的控制器类型和继承的控制器类型不一样的时候,就要取舍,如:继承了UIViewController的控制器就使用不了自带的tableView或者是collectionView的功能,要自己手动添加


    59586B22-0726-4482-B7C8-9BE087590ADB.png
  • 将返回按钮统一交给navigationController统一管理,通过重写- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated方法,判断是否设置返回按钮

  • navigationViewController的子控制器,或者tabBarViewCotnroler的子控制的backgroundColor不要写在navigationViewController和tabBarViewCotnroler中,要写在子控制中的viewDidLoad中,不然会在创建navigationViewController和tabBarViewCotnroler时,会:
    1.提前创建子控制(子控制器是懒加载的,显示的时候子控制器才会被创建,设置背景颜色后就会被提前创建)
    2.提前执行子控制器中viewDidLoad的方法
    最好在push之后再执行子控制器的viewDidLoad的方法,不然重写navigationViewController以后,会覆盖子控制器写的返回按钮代码

  • 无论是通过代码创建还是storyBoard创建navigationViewController,跳转的时候都会调用(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容