基础介绍
| 内容 | 作用 |
|---|---|
| UINavigationController | 是一个容器类,对ViewController进行栈管理,包含navigationBar。 |
| UINavigationBar | 即UINavigationController顶部的导航栏,主要负责外观背景的展示,并对navigationItem进行栈管理 |
| UINavigationItem | 是导航栏上显示的具体的元素的一个抽象类,UINavigationController 通过Category的方法为ViewController添加了一个navigationItem,把UINavigationItem交由ViewController管理 |
/// UINavigationController包含了viewcontrollers、navigationbar、toolbar
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) @interface UINavigationController : UIViewController
// 导航栏
@property(nonatomic,readonly) UINavigationBar *navigationBar; // The navigation bar managed by the controller. Pushing, popping or setting navigation items on a managed navigation bar is not supported.
// 栈里的视图控制器数组
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers; // The current view controller stack.
// toolbar对象
@property(null_resettable,nonatomic,readonly) UIToolbar *toolbar API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(tvos); // For use when presenting an action sheet.
/// 包含当前控制器导航栏上用户自定义视图、和下级视图导航栏控制器
@class UIView, UINavigationBar, UINavigationItem, UIToolbar;
@protocol UINavigationControllerDelegate;
@interface UIViewController (UINavigationControllerItem)
// 当前控制器导航栏上用户自定义视图
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem; // Created on-demand so that a view controller may customize its navigation appearance.
// push时,隐藏底部菜单栏
@property(nonatomic) BOOL hidesBottomBarWhenPushed API_UNAVAILABLE(tvos); // If YES, then when this view controller is pushed into a controller hierarchy with a bottom bar (like a tab bar), the bottom bar will slide out. Default is NO.
// 下级视图的导航控制器
@property(nullable, nonatomic,readonly,strong) UINavigationController *navigationController; // If this view controller has been pushed onto a navigation controller, return it.
/// UINavigaitonBar就是导航栏 主要对UINavigationItem进行栈管理 展示导航栏的外观背景
@class UINavigationItem, UIBarButtonItem, UIImage, UIColor, UINavigationBarAppearance;
@protocol UINavigationBarDelegate;
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) @interface UINavigationBar : UIView <NSCoding, UIBarPositioning>
// 当前push栈中最上层的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *topItem;
// 仅次于最上层的item,一般式被推向导航栏左侧的item
@property(nullable, nonatomic,readonly,strong) UINavigationItem *backItem;
// 获取push栈中所有item的数组
@property(nullable,nonatomic,copy) NSArray<UINavigationItem *> *items;
/// UINavigationItem包含了title,titleView,prompt,leftBarButtonItem,rightBarButtonItem,backBarButonItem等当前页面上所有的信息
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) @interface UINavigationItem : NSObject <NSCoding>
// 设置导航栏中间的内容标题
@property(nullable, nonatomic,copy) NSString *title; // Title when topmost on the stack. default is nil
// 设置导航栏中间的内容视图
@property(nullable, nonatomic,strong) UIView *titleView; // Custom view to use in lieu of a title. May be sized horizontally. Only used when item is topmost on the stack.
// 提示描述 (添加该描述以后NavigationBar的高度会增加30,由44变为74)
@property(nullable,nonatomic,copy) NSString *prompt API_UNAVAILABLE(tvos); // Explanatory text to display above the navigation bar buttons.
// 返回操作键
@property(nullable,nonatomic,strong) UIBarButtonItem *backBarButtonItem API_UNAVAILABLE(tvos); // Bar button item to use for the back button in the child navigation item.
// 左边?操作Item数组
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *leftBarButtonItems API_AVAILABLE(ios(5.0));
// 右边?操作Item数组
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *rightBarButtonItems API_AVAILABLE(ios(5.0));
// 左边?操作Item
@property(nullable, nonatomic,strong) UIBarButtonItem *leftBarButtonItem;
// 右边?操作Item
@property(nullable, nonatomic,strong) UIBarButtonItem *rightBarButtonItem;
/// 一个可以放置在Bar之上的所有小控件类的抽象类,可以设置标题,图片等
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) @interface UIBarItem : NSObject <NSCoding, UIAppearance>
@property(nullable, nonatomic,copy) NSString *title; // default is nil
@property(nullable, nonatomic,strong) UIImage *image; // default is nil
/// 继承UIBarItem,增加了动作以及目标等button的属性。相当于放在UIToolBar或者UINavigationBar上的特殊的button。
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) @interface UIBarButtonItem : UIBarItem <NSCoding>
@property(nullable, nonatomic) SEL action; // default is NULL
@property(nullable, nonatomic,weak) id target; // default is nil
通俗地说就是,UINavigationController是个容器,里面可以装很多UIViewController。装这么多UIViewController让用户怎么控制它们呢?总得有个工具吧,这个工具就是UINavigationBar。一个容器就这么一个bar,相当于控制台。但是管理那么多UIViewController,控制台上得按钮啊、标题啊,都千篇一律是不是看起来太无聊了。为了解决这个问题,UINavigationController为每个UIViewController生成一个UINavigationItem,通过这个UINavigationItem可以改变控制台“上面”的按钮和标题。如果你不自定义UINavigationItem,UINavigationController会使用默认的;

-(void)changeNavigationBarBackgroundColor {
//背景色
self.navigationBar.barTintColor = [UIColor orangeColor];
//title字体
[self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont systemFontOfSize:17]}];
//修改UIBarButtonItem 图片 title颜色
self.navigationBar.tintColor = [UIColor redColor];
//是否半透明 当为YES时 设置的导航栏背景颜色会和实际rgb值有误差
self.navigationBar.translucent = NO;
//如果想要半透明效果 颜色没有色差 可以通过设置背景图片的方法 背景图片会覆盖barTintColor
//- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics
}
默认是nil。当非nil时,显示一个自定义的阴影图像代替默认的阴影图像。要显示一个自定义的阴影,自定义的背景图像也必须使用-setBackgroundImage:forBarMetrics:(设置shadowImage必须先setBackgroundImage,否则无法实现效果)。


-(void)changeNavigationBarBottonLine {
//设置底部line颜色时需要同时设置backgroundImage即导航栏的背景图片 否则没有效果
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[self imageWithColor:[ UIColor redColor]]];
//此处设置透明颜色的image,底部line即可隐藏,但此种方法隐藏,没有办法再显示 下面方法通过找到该view 控制其hidden属性
//[self reducibilityHiddenNavogationBarLine];
}
-(UIImage*)imageWithColor:(UIColor*)color {
CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
找到该imageView
-(UIImageView *)findLineImageViewUnder:(UIView *)view {
if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1.0) {
return (UIImageView *)view;
}
for (UIView * subView in view.subviews) {
UIImageView * imageView = [self findLineImageViewUnder:subView];
if (imageView) {
return imageView;
}
}
return nil;
}
自定义文字+图片

-(void)createCustomBackBarItem {
//修改图片文字颜色
self.navigationController.navigationBar.tintColor = [UIColor orangeColor];
//替换图片
[self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"返回"]];
[self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"返回"]];
//设置文字
UIBarButtonItem * backBarItem = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backBarItem;
}
对backBarButtonItem的修改是在当前viewController前一个页面完成的,在当前页面修改针对下一个viewController的navigationItem生效
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -100) forBarMetrics:UIBarMetricsDefault];
设置Title在Y方向上的偏移量,使其移除屏幕,该方法在第一次进入时会有个文字移动的动画效果,效果不好,不推荐使用
-(void)setLeftBarItemBack
{
UIBarButtonItem *leftBarBtnItem = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:@"back"] style:UIBarButtonItemStylePlain target:self action:@selector(clickLeftBarBtnItem:)];
[self.navigationItem setLeftBarButtonItem:leftBarBtnItem animated:YES];
self.navigationItem.leftBarButtonItem.tintColor = NavigationLeftBackColor;
}
/**
* 导航条leftBarBtn事件
*/
- (void)clickLeftBarBtnItem:(UIBarButtonItem *)sender {
[self.navigationController popViewControllerAnimated:YES];
}
使用这种方法,不能使用边缘滑动返回手势,且不能同时设置图片和标题
1.如果B视图有一个自定义的左侧按钮(leftBarButtonItem),则会显示这个自定义按钮;
2.如果B没有自定义按钮,但是A视图的backBarButtonItem属性有自定义项,则显示这个自定义项;
3.如果前2条都没有,则默认显示一个后退按钮,后退按钮的标题是A视图的标题;
此方法不适于backBarButtonItem,只能用于leftBarButtonItem
self.navigationController.interactivePopGestureRecognizer.delegate = self;
一般情况下都是正常的。但是在偶然情况下,会出现在进入新界面后,新界面的navigationBar会突然消失,出现的还是上一个界面的 navigationBar。从此以后,navigationBar 全乱了, kill 掉重新进,恢复正常。
原因:
一般我们会打点调用navigationBarHidden的属性来设置导航栏是否隐藏,这种方法是不带动画效果的。这样偶尔就会导致错乱,这应该是一个系统的bug,所以应尽量使用
self.navigationItem.title = @"my title"; //sets navigation bar title.
self.tabBarItem.title = @"my title"; //sets tab bar title.
self.title = @"my title"; //sets both of these.
- 如果当前VC通过
self.navigationItem.titleView指定了自定义的titleView,系统将会显示指定的titleView,设置self.title以及self.navigationItem.title不会改变导航栏的标题。- 如果当前VC没有指定titleView,系统则会根据当前VC的title或者当前VC的navigationItem.title的内容创建一个UILabel并显示。
- self.title会重写navigationItem和tabBarItem的title。
navigationItem是UIViewController的一个属性,navigationController继承UIViewController,自然会继承viewControoler的navigationItem属性。此处self.navigationController.navigationItem是应该被忽视的。navigationItem直接由viewController管理。
typedef NS_ENUM(NSInteger, UIBarMetrics) {
UIBarMetricsDefault, //横屏
UIBarMetricsCompact,//竖屏
UIBarMetricsDefaultPrompt = 101, //横屏且设置了prompt属性 Applicable only in bars with the prompt property, such as UINavigationBar and UISearchBar
UIBarMetricsCompactPrompt, //竖屏且设置了prompt属性
};
typedef NS_ENUM(NSInteger, UIBarPosition) {
UIBarPositionAny = 0, //Bar在任何位置
UIBarPositionBottom = 1, //Bar在底部
UIBarPositionTop = 2, //Bar在顶部
UIBarPositionTopAttached = 3, //Bar在顶部,且他的背景扩展到statusBar的区域
} NS_ENUM_AVAILABLE_IOS(7_0);
self.navigationController.navigationBarHidden或者self.navigationController.navigationBar.hidden来隐藏navigatiuonbar,这样直接更改属性的方式是不带动画的,而且滑动时的转场动画也不为我们处理好,才导致了问题的出现,而- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated;为我们完美的解决这样的问题
#define kStatusBarHeight \
^(){\
if (@available(iOS 15.0, *)) {\
CGFloat height = 0.0f;\
NSSet *scenes = [[UIApplication sharedApplication] connectedScenes];\
for (UIScene *scene in scenes) {\
if ([scene isKindOfClass:[UIWindowScene class]]) { \
UIWindowScene *windowScene = (UIWindowScene*)scene;\
height = windowScene.statusBarManager.statusBarFrame.size.height;\
}\
}\
return height;\
} else if (@available(iOS 13.0, *)) {\
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager;\
return statusBarManager.statusBarFrame.size.height;\
} else {\
return [UIApplication sharedApplication].statusBarFrame.size.height;\
}\
}()
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#
我正在尝试将全局导航菜单项添加到我的ActiveAdmin安装(在“仪表板”导航按钮旁边)。ActiveAdmin说这在他们的网站上是可能的,但他们没有任何关于如何实现它的文档。有谁知道如何做到这一点?编辑:抱歉,我应该更清楚。我想添加一个指向由任意文本/链接对组成的全局导航的链接。IE,如果我想添加一个链接到http://google.com在事件管理员的全局导航中使用文本“Google”,我将如何实现? 最佳答案 ActiveAdmin.register_page"Google"domenu:priority=>1,:label
当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab
我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文
在ruby中...我有一个由外部进程创建的IO对象,我需要从中获取文件名。然而我似乎只能得到文件描述符(3),这对我来说不是很有用。有没有办法从此对象获取文件名甚至获取文件对象?我正在从通知程序中获取IO对象。所以这也可能是获取文件路径的一种方式? 最佳答案 关于howtogetathefilenameinC也有类似的问题,我将在这里以ruby的方式给出这个问题的答案。在Linux中获取文件名假设io是您的IO对象。以下代码为您提供了文件名。File.readlink("/proc/self/fd/#{io.fileno}")例
伴随农业机械化和智能化的发展,越来越多的人开始使用农机自动驾驶系统助力耕作,千耘农机导航的“星地一体”能力可有效解决信号受限的问题,实现作业提效。究竟什么是“星地一体”,又是如何解决智能化农机作业的痛点的?下面为大家揭秘。农机效率通常受限于通信网络目前虽然我国通讯网络的人口覆盖率达到99%,但地面移动通讯网络覆盖率仍小于国土面积的40%,而很多农田所在区域恰是山区、戈壁滩等偏远地区。两省交界地也会出现通信信号不稳定的状况;而国内大部分农机自动驾驶系统非常依赖通信网络,当通信网络弱的时候会出现系统掉线的现象,必须得携带小基站才能正常使用,极为繁琐。Q:什么是千耘农机导航“星地一体”能力?A:是星