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

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

作者: 枫之叶_小乙哥 | 来源:发表于2016-12-13 10:58 被阅读19次

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

相关文章

网友评论

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

      本文链接:https://www.haomeiwen.com/subject/hbwvmttx.html