0.OC中两种获取类的方式
-
NSSClassFromString(@"UITabBarButton")
-
[UITabBarButton class]
-
比较两个类是否相同的
subView.class != NSSClassFromString(@"UITabBarButton")[@"UITabBarButton"� isEqualToString:NSSClassFromString(subView.class)]
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
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决定的
/**** 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.设置返回按钮的两种方法
- 第一种方法
- 第二种方法
第二种方法将按钮数组直接穿进去,不用设置frame,推荐使用.
11.因为返回按钮经常用到,如果要统一设置自定义返回按钮(如果不自定义返回按钮,则返回的按钮会显示上个控制器的标题,而不是"返回"字眼),有两种方法:自定义类和分类
- 自定义类:继承NSObject,抽取一个类来专门管理返回btn
-
分类:创建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
网友评论