iOSナビゲーションバー制御のまとめ


前言
久しぶりにUIを書かないと、UIに関することが多くなりました。最近はナビゲーションバーを使っていろいろな場面をまとめました。
1.ナビゲーションバーの表示と非表示
ナビゲーションバーの表示と非表示は、2つの場合に分けられます。
1.ナビゲーションバーのページプッシュからナビゲーションバーのページを表示しません。
2.ナビゲーションバーが表示されているページから、ナビゲーションバーが表示されていないページにジャンプします。
注意:
1.ナビゲーションバーが表示されていない場合、システムの横滑りリターン機能は無効です。
2.横滑りリターン機能は無効ですが、ナビゲーションバーの.interactivePopGestureRecognizer.delegateはまだあります。
上記の2つの状況に対してそれぞれ処理します。Pushプロセス全体はAページからBページにジャンプしたと仮定します。
1.1ナビゲーションバーのページPushからナビゲーションバーのページを表示しません。
ナビゲーションバーの表示については、スライドに沿っているかどうかは、次の2つの方法で制御されます。

//      ,          
[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.ナビゲーションバーを一括して書き換える戻るボタン
時には、同じ工程で戻るボタンのスタイルが必要かもしれません。たとえば、矢印+戻りまたは矢印です。
スキームには2つの種類があります
1.BaseView Controllerを作成し、navigationItem.leftBarButtonItemを一括設定する。
2.ナビゲーションコントローラのPush方法を書き換え、Pushの前にnavigationItem.backBarButtonItemを設定します。
注意:
ナビゲーションバーのleftBarButonItemを書き換えると、横滑りでリターン機能が無効になり、横滑りでリターン機能が必要になります。
第一の案は比較的簡単であり、詳細な説明はしない。第二の案はこのようなものである。
ナビゲーションコントローラをカスタマイズして、次の方法を書き換えます。

- (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として無駄です。
しかし、システムの戻りボタンを書き換えたことがないと、このような状況を処理するのが面倒くさいです。
処理手順は以下の通りです。
1.まずUID View Controllerのカテゴリを作成します。ヘッダファイル(.h)の内容は以下の通りです。

@protocol BackItemProtocol <NSObject>

- (BOOL)navigationShouldPopWhenBackButtonClick;

@end

@interface UIViewController (BackItem)<BackItemProtocol>

@end

@interface UINavigationController (BackItem)

@end
一つのプロトコル、UIView Controllerの種類、UninavigationControllerの種類を含みます。
そして、実現ファイル(.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
デフォルトでは、リターンボタンのイベントを処理する必要がなく、直接システムのポップメソッドを使用します。
しかし、ユーザーがリターンボタンをクリックしたい時には、このカテゴリを導入する必要があります。
次に、方法を書き換えます。

- (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.ナビゲーションコントローラのページ移動方法
安卓中のページジャンプには4つの方法があります。スタンダード、singleTop、singleTask、singleInstance。
例えば、singleTaskは、IMクラスAppを作ってチャットルームにジャンプするシーンで、非常に有用であり、コントローラスタックの中にはチャットルームが一つしかないので、リターン時に階層が深すぎないようにすることができます。
iOS端末がこの効果をまねるなら、ナビゲーションコントローラのAPIを利用することができます。

- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated
まず、UITNavigationControllerのためにカテゴリを作成します。
たとえば:

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;
そして、実現方法:
実装ステップ:
  • は、新しい配列コピーナビゲーションコントローラの元のスタック内のコントローラを作成します。
  • は、元のスタック配列において、このタイプのコントローラが存在するかどうかを判断し、そのインデックスが記録されている場合。
  • は、コピーされた配列内でインデックスおよび上のすべてのコントローラを削除する。
  • は、プッシュしたいコントローラをコピーされた配列に追加します。
  • は、新しいコントローラ配列をナビゲーションコントローラのスタック配列として設定し、パラメータに基づいてアニメーションを表示するかどうかを判断する。
  • 私はいくつかの発散をしましたが、いくつかの種類には多くのサブクラスがあるかもしれませんので、親およびサブクラスのインスタンスは一つしかないと保証したいです。だから、方法を改善しました。
    
    - (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];
    }
    
    もちろん、上記のようなシーン以外にも、プッシュボタンを押して戻ったり、横に滑ったりすると、指定のページに直接戻ってくるなど、他のシーンが広がっています。
    あるいは、戻るページの種類を知っています。直接にページを指定します。
    拡張された他の方法は全部デモの中にあります。興味があったら見てください。
    住所はHLProjectです。 ( ローカルダウンロード
    締め括りをつける
    以上はこの文章の全部の内容です。本文の内容は皆さんの学習や仕事に対して一定の参考学習価値を持ってほしいです。ありがとうございます。