返回顶部
首页 > 资讯 > 移动开发 >iOS导航栏控制的一些总结
  • 249
分享到

iOS导航栏控制的一些总结

ios导航栏控制 2022-05-27 03:05:56 249人浏览 泡泡鱼
摘要

前言 许久不写UI,对UI的很多东西都生疏了,最近使用导航栏的各种场景做一些总结。 1.导航栏的显示与隐藏 导航栏的显示与隐藏,分两种情况: 从不显示导航栏的页面push到显示导

前言

许久不写UI,对UI的很多东西都生疏了,最近使用导航栏的各种场景做一些总结

1.导航栏的显示与隐藏

导航栏的显示与隐藏,分两种情况:

从不显示导航栏的页面push到显示导航栏的页面。

从显示导航栏的页面Push到不显示导航栏的页面。

注意:

如果导航栏不显示时,系统的侧滑返回功能无效。

虽然侧滑返回功能无效,但是导航栏的 .interactivePopGestureRecognizer.delegate还是存在的。

针对以上两种情况分别处理,整个Push过程都假设是从A页面跳转到B页面

1.1 从不显示导航栏的页面Push到显示导航栏的页面。

关于导航栏的显示,是否顺滑,是通过如下两个方法来控制。


// 不显示动画,导航栏显示就比较突兀
[self.navigationController setNavigationBarHidden:YES];

// 显示动画,在侧滑时,导航栏显示就比较顺滑
[self.navigationController setNavigationBarHidden:YES animated:YES];

所以,做法是:

A页面:


- (void)viewWillAppear:(BOOL)animated
{
 [super viewWillAppear:animated];
 
 [self.navigationController setNavigationBarHidden:YES animated:YES];
}

B页面:


- (void)viewWillAppear:(BOOL)animated
{
 [super viewWillAppear:animated];
 
 [self.navigationController setNavigationBarHidden:NO animated:YES];
}

1.2 从显示导航栏的页面跳转到不显示导航栏的页面

这种情况的做法如下:

A页面:


- (void)viewWillAppear:(BOOL)animated
{
 [super viewWillAppear:animated];
 [self.navigationController setNavigationBarHidden:NO animated:YES];
}

B页面:


// 在页面将要出现时,记录原始侧滑手势代理对象,并将手势代理设置为当前页面
- (void)viewWillAppear:(BOOL)animated
{
 [super viewWillAppear:animated];
 
 self.interactivePopDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
 self.navigationController.interactivePopGestureRecognizer.delegate = self;
 
 [self.navigationController setNavigationBarHidden:YES animated:YES];
}

// 在页面消失时,还原侧滑手势代理对象
- (void)viewDidDisappear:(BOOL)animated
{
 [super viewDidDisappear:animated];
 
 self.navigationController.interactivePopGestureRecognizer.delegate = self.interactivePopDelegate;
 self.interactivePopDelegate = nil;
}

// 实现手势代理,为了防止影响其他手势,可以判断一下手势类型
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
 if ([gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]) {
 return YES;
 }
 ...... 其他手势的处理
 
 
 return NO;
}

2.统一重写导航栏返回按钮

有时候,我们可能需要统一工程中的返回按钮样式,比如都是 箭头+返回 或者都是 箭头。

方案有两种:

创建一个BaseViewController,然后统一设置navigationItem.leftBarButtonItem

重写导航控制器的Push方法,在push之前,设置navigationItem.backBarButtonItem

注意:

如果重写了导航栏的leftBarButtonItem,那么侧滑返回功能也就失效了,需要侧滑返回功能需要自己处理。

第一种方案比较简单就不做赘述了,第二种方案是这样的:

自定义导航控制器,然后重写如下方法:


- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
 UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:nil action:nil];
 viewController.navigationItem.backBarButtonItem = backItem;
 
 [super pushViewController:viewController animated:animated];
}

如果不需要返回这两个字,只需要这样写就好。


- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
 UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:nil style:UIBarButtonItemStyleDone target:nil action:nil];
 viewController.navigationItem.backBarButtonItem = backItem;
 
 [super pushViewController:viewController animated:animated];
}

3.监听返回按钮的点击事件

在有些场景,我们需要监听返回按钮的事件。比如,当页面用户输入了一些内容后,用户要点击返回,想要回到上一个页面时,提醒用户是否要缓存已经输入的内容。

如果我们重写了导航栏的返回按钮,那么处理这种情况就很Easy,不做赘述了。

但是,如果我们没有重写过系统的返回按钮,想要处理这种情况就比较麻烦,但是也是可以处理的。

处理步骤如下:

首先创建一个UIViewController的类别,头文件(.h)的内容如下:


@protocol BackItemProtocol <NSObject>

- (BOOL)navigationShouldPopWhenBackButtonClick;

@end

@interface UIViewController (BackItem)<BackItemProtocol>

@end

@interface UINavigationController (BackItem)

@end

包含一个协议、UIViewController的类别、UINavigationController的类别。

然后,实现文件(.m)如下:


#import "UIViewController+BackItem.h"

@implementation UIViewController (BackItem)

- (BOOL)navigationShouldPopWhenBackButtonClick
{
 return YES;
}

@end


@implementation UINavigationController (BackItem)

// 这个其实是导航栏的协议方法,在这里重写了
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
 if([self.viewControllers count] < [navigationBar.items count]) {
 return YES;
 }
 
 BOOL shouldPop = YES;
 UIViewController *vc = [self topViewController];
 if([vc respondsToSelector:@selector(navigationShouldPopWhenBackButtonClick)]) {
 shouldPop = [vc navigationShouldPopWhenBackButtonClick];
 }
 
 if (shouldPop) {
 dispatch_async(dispatch_get_main_queue(), ^{
 [self popViewControllerAnimated:YES];
 });
 } else {
 for(UIView *subview in [navigationBar subviews]) {
 if(subview.alpha < 1) {
 [UIView animateWithDuration:.25 animations:^{
  subview.alpha = 1;
 }];
 }
 }
 }
 return NO;
}

@end

默认是,不需要处理返回按钮的事件,直接使用系统的pop方法。

但是,如果我们需要在用户点击返回按钮时,弹窗提示,那就需要导入这个类别。

然后,重写一个方法:


- (BOOL)navigationShouldPopWhenBackButtonClick
{
 BOOL isFlag = 输入框不为空等等条件
 if (isFlag) {
 UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:@"是否保存修改" preferredStyle:UIAlertControllerStyleAlert];
 UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 // 这里延时执行是因为UIAlertController阻塞UI,可能会导致动画的不流畅
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 [self.navigationController popViewControllerAnimated:YES];
 });
 }];
 UIAlertAction *saveAction = [UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 // 这里延时执行是因为UIAlertController阻塞UI,可能会导致动画的不流畅
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 [self rightClick];
 });
 }];
 [alertVC addAction:cancelAction];
 [alertVC addAction:saveAction];
 [self presentViewController:alertVC animated:YES completion:nil];
 return NO;
 }
 
 return YES;
}

4.导航控制器的页面跳转方式

安卓中的页面跳转有四种方式: standard、singleTop、singleTask、singleInstance。

例如singleTask,在做IM类App,跳转到聊天室的场景,就非常有用,可以保证控制器栈中只有一个聊天室,避免返回时层级太深。

iOS端如果要仿这个效果的话,可以利用导航控制器的api


- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated

首先,为UINavigationController 创建一个类别。

比如:


UINavigationController+HLPushAndPop.h
UINavigationController+HLPushAndPop.m

然后,新增几个方法:

拿两个方法来举例


- (void)hl_pushSingleViewController:(UIViewController *)viewController
  animated:(BOOL)animated;

- (void)hl_pushSingleViewController:(UIViewController *)viewController
  parentClass:(Class)parentClass
  animated:(BOOL)animated;

再然后,实现方法:

实现步骤:

  1. 创建新的数组复制导航控制器原来的堆栈中的控制器。
  2. 在原始堆栈数组中判断是否存在该类型的控制器,如果存在记录其索引
  3. 在复制的数组中将索引及上方所有控制器移除。
  4. 把将要push出来的控制器添加到复制的数组中。
  5. 将新的控制器数组设置为导航控制器的栈数组,根据参数判断是否要显示动画。

我这边做了一些发散,因为一些类可能会有很多子类,那么想要保证父类以及子类的实例都只有一个,所以将方法做了改进。


- (void)hl_pushSingleViewController:(UIViewController *)viewController
  animated:(BOOL)animated
{
 [self hl_pushSingleViewController:viewController parentClass:viewController.class animated:animated];
}

- (void)hl_pushSingleViewController:(UIViewController *)viewController
  parentClass:(Class)parentClass
  animated:(BOOL)animated
{
 if (!viewController) {
 return;
 }
 // 如果要push的界面不是 parentClass以及其子类的实例,则按照方法1处理
 if (![viewController isKindOfClass:parentClass]) {
 [self hl_pushSingleViewController:viewController animated:animated];
 return;
 }
 
 // 判断 导航控制器堆栈中是否有parentClass以及其子类的实例
 NSArray *childViewControllers = self.childViewControllers;
 NSMutableArray *newChildVCs = [[NSMutableArray alloc] initWithArray:childViewControllers];
 BOOL isExit = NO;
 NSInteger index = 0;
 for (int i = 0; i < childViewControllers.count; i++) {
 UIViewController *vc = childViewControllers[i];
 if ([vc isKindOfClass:parentClass]) {
 isExit = YES;
 index = i;
 break;
 }
 }
 
 // 如果不存在,则直接push
 if (!isExit) {
 [self pushViewController:viewController animated:animated];
 return;
 }
 
 // 如果存在,则将该实例及上面的所有界面全部弹出栈,然后将要push的界面放到栈顶。
 for (NSInteger i = childViewControllers.count - 1; i >= index; i--) {
 [newChildVCs removeObjectAtIndex:i];
 }
 
 [newChildVCs addObject:viewController];
 viewController.hidesBottomBarWhenPushed = (newChildVCs.count > 1);
 [self setViewControllers:newChildVCs animated:animated];
}

当然了,除了上面这些场景,还可以扩展出一些其他的场景,比如我们期望将要push出来的控制器再某个栈中控制器的后面或者前面,这样当点击返回或者侧滑时,就直接回到了指定页面了。

或者我们知道将要返回的页面的类型,直接pop回指定页面。

扩展出来的其他方法都在Demo中了,有兴趣的可以看一下。

地址是:HLProject (本地下载

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对编程网的支持。

--结束END--

本文标题: iOS导航栏控制的一些总结

本文链接: https://lsjlt.com/news/30300.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • iOS导航栏控制的一些总结
    前言 许久不写UI,对UI的很多东西都生疏了,最近使用导航栏的各种场景做一些总结。 1.导航栏的显示与隐藏 导航栏的显示与隐藏,分两种情况: 从不显示导航栏的页面push到显示导...
    99+
    2022-05-27
    ios 导航栏 控制
  • iOS状态栏、导航栏的一些笔记分享
    前言 IOS的界面分为状态栏和导航栏,如下图所示: 状态栏与导航栏的位置如上图,我们可以通过[UIApplication sharedApplication].statusBarF...
    99+
    2022-05-27
    ios 状态栏 导航栏
  • iOS导航栏对控制器view的影响详解
    前言 当我们设置导航栏的某些属性的时候会导致控制器View的布局不是从window的 (0,0)点开始布局,会从导航栏底部开始布局,而此时在 viewDidLoad 中 获取到Vie...
    99+
    2022-05-18
    ios 导航栏 控制器
  • 简单好用的iOS导航栏封装.runtime属性控制实例代码
    前言 本文主要给大家介绍一个不错的导航栏控制工具,可以大大的简化代码,并保留系统特性,不用自定义导航栏,不用继承base。 下面话不多说了,来一起看看详细的介绍吧 UIViewCon...
    99+
    2022-05-16
    导航栏 封装 .runtime
  • iOS隐藏导航栏线的代码怎么写
    在iOS中,可以通过以下代码隐藏导航栏的分割线:```// 隐藏导航栏底部的分割线navigationController.navi...
    99+
    2023-08-16
    iOS
  • web开发中如何制作一级导航栏
    这篇文章将为大家详细讲解有关web开发中如何制作一级导航栏,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。第一步:引入css样式表,新建一个id为nav的层,使用<u...
    99+
    2024-04-02
  • iOS中WKWebView的一些特殊使用总结
    前言 现在大部分的app只支持iOS8以上的系统了,在接入H5时可以只管最新的WKWebView了。 WKWebView的优势 性能高,稳定性好,占用的内存比较小, 支持...
    99+
    2022-05-23
    ios wkwebview 特殊
  • iOS开发之隐藏导航栏线的简单代码
    在 iOS 开发中,要隐藏导航栏线,可以使用以下简单的代码:Objective-C:```objective-c// 在 viewD...
    99+
    2023-08-15
    iOS
  • iOS开发之导航栏各种右滑返回失效的解决方法汇总
    前言 众所周知iOS 的几乎全部页面都是需要右滑返回的,否则用户体验会大打折扣,但是在开发过程中经常会碰到某些页面右滑返回失效的情况,下面记录一下各种情况下右滑返回失效的解决方法...
    99+
    2022-05-27
    ios 导航栏 右滑返回
  • 怎么使用HTML制作一个简单美观的导航栏
    小编给大家分享一下怎么使用HTML制作一个简单美观的导航栏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在不久前学习了基础知识(...
    99+
    2024-04-02
  • 怎么使用CSS制作一个简单美观的导航栏
    这篇文章主要讲解了“怎么使用CSS制作一个简单美观的导航栏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用CSS制作一个简单美观的导航栏”吧! ...
    99+
    2024-04-02
  • iOS实现简易的导航栏颜色渐变实例代码
    前言 很多App首页要做成类似天猫和京东的导航栏,实现在页面滑动过程中导航栏渐变的效果。笔者之前在项目里用过一个三方,后来更新版本失效了,于是决定结合自己对导航栏的认识来实现一下这个...
    99+
    2022-06-04
    渐变 导航栏 颜色
  • dedecms实现二级栏目导航的仿制方法
    本文实例讲述了dedecms实现二级栏目导航的仿制方法。分享给大家供大家参考。 具体实现代码如下: 复制代码代码如下:{dede:channelartlist row='2' typeid='1,2' } <h3...
    99+
    2022-06-12
    dedecms 二级栏目 导航 仿制 方法
  • 怎么用html和CSS3制作好看的导航栏
    这篇文章主要介绍“怎么用html和CSS3制作好看的导航栏”,在日常操作中,相信很多人在怎么用html和CSS3制作好看的导航栏问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2024-04-02
  • MariaDB ColumnStore一些限制和BUG总结
    字段属性限制1、不支持CHARACTER SET语法MariaDB [test]> create table t1(id int,name varchar(10) CHARACTER SET...
    99+
    2024-04-02
  • 小程序自定义tabbar导航栏、动态控制tabbar功能实现(uniapp)
    uniapp开发小程序,不同角色/已登录未登录,都有不一样的底部导航栏,这些情况下就需要自行定义tabbar,从而实现动态tabbar的实现。 1.首先我们需要在pages.json配置tabbar...
    99+
    2023-09-02
    uni-app vue.js 前端
  • 如何使用css3制作炫酷的导航栏效果
    本篇内容介绍了“如何使用css3制作炫酷的导航栏效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2024-04-02
  • 如何实现css控制列表与导航的制作
    本篇内容介绍了“如何实现css控制列表与导航的制作”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!代码如下:...
    99+
    2024-04-02
  • 总结MySQL 的一些知识点:MySQL 导入数据
    MySQL 导入数据 本章节我们为大家介绍几种简单的 MySQL 导入数据命令。   1、mysql 命令导入 使用 mysql 命令导入语法格式为: mysql -u用户名 -p密码 < 要导入的数据库数据(kxdang....
    99+
    2023-09-26
    数据库 mysql
  • 制作响应式导航栏:CSS属性的实用技巧
    制作响应式导航栏:CSS属性的实用技巧导航栏是网页中非常重要的部分,直接影响着用户体验和页面的整体布局。在移动设备流行的今天,响应式导航栏显得尤为重要。本文将介绍一些使用CSS属性来制作响应式导航栏的实用技巧,并提供具体的代码示例,帮助你在...
    99+
    2023-11-18
    制作 CSS属性 响应式导航栏
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作