93

プログラムで(IBなしで)UINavigationBarインスタンス化する場合、カスタムサブクラスをどのように使用できるか知っている人はいますか?UINavigationController

IB にドラッグしてUINavigationControllerナビゲーション バーの下に表示し、Identity Inspectory を使用して、クラス タイプを変更し、独自のサブクラスを設定UINavigationBarできますが、プログラムではできませんnavigationBar。Navigation Controller のプロパティは読み取り専用です...

ナビゲーション バーをプログラムでカスタマイズするにはどうすればよいですか? IB は「コード」よりも「強力」ですか? 私は、IB でできることはすべてプログラムでもできると信じていました。

4

12 に答える 12

89

KVCを使用するだけで、XIBをいじる必要はありません。

[self.navigationController setValue:[[[CustomNavBar alloc]init] autorelease] forKeyPath:@"navigationBar"];
于 2012-03-07T23:33:23.347 に答える
67

iOS5 以降、Apple はこれを直接行う方法を提供しています。参照

UINavigationController *navigationController= [[UINavigationController alloc]initWithNavigationBarClass:[CustomNavBar class] toolbarClass:nil];
[navigationController setViewControllers:[NSArray arrayWithObject:yourRootViewController]];
于 2012-09-21T08:48:42.913 に答える
37

iOS 4 以降、UINibクラスを使用してこの問題を解決できます。

  1. カスタムUINavigationBarサブクラスを作成します。
  2. 空の xib を作成UINavigationControllerし、単一のオブジェクトとして a を追加します。
  3. UINavigationControllerのクラスをUINavigationBarカスタム サブクラスに設定します。
  4. 次のいずれかの方法でルート ビュー コントローラーを設定します。
    • [navController setViewcontrollers[NSArray arrayWithObject:myRootVC]];
    • [navController pushViewController:myRootVC];

コード内:

UINib *nib = [UINib nibWithNibName:@"YourCustomXib" bundle:nil];
UINavigationController *navController = 
             [[nib instantiateWithOwner:nil options:nil] objectAtIndex:0];


これUINavigationControllerで、カスタムの ができましたUINavigationBar

于 2011-05-25T00:19:26.797 に答える
26

私が知る限り、非標準のスタイル変更を行うために UINavigationBar をサブクラス化することが実際に必要になる場合があります。カテゴリを使用することで回避できる場合もありますが、常にそうとは限りません。

現在、私の知る限り、UIViewController 内でカスタム UINavigationBar を設定する唯一の方法は IB を使用すること (つまり、アーカイブを使用すること) です。おそらくそのようにするべきではありませんが、今のところは、それと一緒に暮らす必要があります。

多くの場合、これで問題ありませんが、IB の使用が現実的でない場合もあります。

そのため、次の 3 つのオプションがありました。

  1. UINavigationBar をサブクラス化し、IB にすべて接続してから、UINavigationController が必要になるたびに nib をロードすることをいじくりまわします。
  2. サブクラス化ではなく、カテゴリ内でメソッド置換を使用して UINavigationBar の動作を変更する、または
  3. UINavigationBar をサブクラス化し、UINavigationController のアーカイブ/アーカイブ解除を少しいじります。

UINavigationController をプログラムで作成する必要があったため、この場合、オプション 1 は実行不可能でした (または、少なくとも煩わしすぎました)。2 は少し危険であり、最後の手段であると考えているため、オプション 3 を選択しました。

私のアプローチは、UINavigationController の「テンプレート」アーカイブを作成し、それを解凍してinitWithRootViewController.

方法は次のとおりです。

IB では、UINavigationBar に適切なクラス セットを使用して UINavigationController を作成しました。

次に、既存のコントローラを取得し、.xml を使用してそのアーカイブ コピーを保存しました+[NSKeyedArchiver archiveRootObject:toFile:]。シミュレーターのアプリデリゲート内でこれを行いました。

次に、「xxd」ユーティリティを -i フラグとともに使用して、保存したファイルから C コードを生成し、アーカイブ バージョンをサブクラスに組み込みました ( xxd -i path/to/file)。

その中でinitWithRootViewController、そのテンプレートを解凍し、解凍の結果を self に設定します。

// This is the data from [NSKeyedArchiver archivedDataWithRootObject:controller], where
// controller is a CTNavigationController with navigation bar class set to CTNavigationBar,
// from IB.  This c code was created using 'xxd -i'
static unsigned char archived_controller[] = {
    0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03,
    ...
};
static unsigned int archived_controller_len = 682;

...

- (id)initWithRootViewController:(UIViewController *)rootViewController {
     // Replace with unarchived view controller, necessary for the custom navigation bar
     [self release];
     self = (CTNavigationController*)[NSKeyedUnarchiver unarchiveObjectWithData:[NSData dataWithBytes:archived_controller length:archived_controller_len]];
     [self setViewControllers:[NSArray arrayWithObject:rootViewController]];
     return [self retain];
}

次に、カスタム ナビゲーション バー セットを持つ UIViewController サブクラスの新しいインスタンスを取得します。

UIViewController *modalViewController = [[[CTNavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
[self.navigationController presentModalViewController:modalViewController animated:YES];

これにより、ナビゲーション バーとツールバーがすべて設定され、カスタム ナビゲーション バー クラスが配置されたモーダル UITableViewController が得られます。少し厄介なメソッドの置換を行う必要はありませんでした。また、本当にプログラムで作業したいだけの場合でも、ペン先をいじる必要はありません。

+layerClassUINavigationController 内で同等のものを見たいのです+navigationBarClassが、今のところ、これは機能します。

于 2010-06-20T19:33:27.553 に答える
5

私は「オプション1」を使用します

UINavigationController のみを含む nib ファイルを作成します。UINavigationBar クラスをカスタム クラスに設定します。

self.navigationController = [[[NSBundle mainBundle] loadNibNamed:@"navigationbar" owner:self options:nil] lastObject];

[navigationController pushViewController:rootViewController animated:YES];
于 2010-12-17T00:53:11.327 に答える
5

Michael のソリューションは機能しますが、NSKeyedArchiver と 'xxd' ユーティリティを避けることができます。UINavigationController をサブクラス化してオーバーライドinitWithRootViewControllerし、カスタム NavigationController NIB を直接ロードします。

- (id) initWithRootViewController:(UIViewController *)rootViewController
{
    [self release];
    self = [[[[NSBundle mainBundle] loadNibNamed:@"CTNavigationController" owner:nil options:nil] objectAtIndex:0] retain];  
    [self setViewControllers:[NSArray arrayWithObject:rootViewController]];
    return self;
}
于 2011-10-20T12:57:19.713 に答える
4

更新:object_SetClass() iOS5 GM のように使用できなくなりました。代替ソリューションが以下に追加されました。

NSKeyedUnarchiver を使用して、ナビゲーション バーの unarchive クラスを手動で設定します。

   MyViewController *controller = [[[MyViewController alloc] init] autorelease];
   NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:[NSKeyedArchiver archivedDataWithRootObject:controller]] autorelease];
   [unarchiver setClass:[MyNavigationBar class] forClassName:@"UINavigationBar"];
   controller = [unarchiver decodeObjectForKey:@"root"];




注: この元のソリューションは、iOS5 より前のバージョンでのみ機能します。

ここに投稿した素晴らしい解決策があります-navBarサブクラスをビューに直接挿入しますUINavigationController

#import <objc/runtime.h>

- (void)viewDidLoad {
    [super viewDidLoad];

    object_setClass(self.navigationController.navigationBar, [MyNavBar class]);
    // the rest of your viewDidLoad code
}
于 2011-10-06T19:27:20.263 に答える
1

これらのカテゴリ メソッドは危険であり、初心者向けではありません。また、iOS4 と iOS5 の違いによる複雑さにより、これは多くの人にとってバグを引き起こす可能性のある領域になります。これは、iOS4.0 ~ iOS6.0 をサポートする、非常に単純な単純なサブクラスです。

.h

@interface XXXNavigatioNBar : UINavigationBar
@end

.m

#import "XXXNavigationBar.h"

#import <objc/runtime.h>

@implementation XXXNavigationBar

- (void) didMoveToSuperview {
    if( [self respondsToSelector: @selector(setBackgroundImage:forBarMetrics:)]) {
        //iOS5.0 and above has a system defined method -> use it
        [self setBackgroundImage: [UIImage imageNamed: @"nav-bar"]
                   forBarMetrics: UIBarMetricsDefault];
    }
    else {
        //iOS4.0 requires us to override drawRect:. BUT!!
        //If you override drawRect: on iOS5.0 the system default will break,
        //so we dynamically add this method if required
        IMP implementation = class_getMethodImplementation([self class], @selector(iOS4drawRect:));
        class_addMethod([self class], @selector(drawRect:), implementation, "v@:{name=CGRect}");
    }
}

- (void)iOS4drawRect: (CGRect) rect {
    UIImage* bg = [UIImage imageNamed:@"nav-bar-blue"];
    [bg drawInRect: rect];
}

@end
于 2012-10-01T08:35:16.547 に答える
1

カテゴリではなくサブクラスを使用する必要があることがわかった 1 つのシナリオは、パターン イメージでナビゲーションバーの背景色を設定することです。ios3.1-5.0 をサポートしたい場合は、navigationbar をサブクラス化するしかありません。

于 2011-11-30T23:31:01.617 に答える
0

クラスをサブクラス化することはお勧めしませんUINavigationBar。ナビゲーション バーをカスタマイズするための推奨される方法は、そのプロパティを設定して希望どおりに表示し、デリゲートと共に UIBarButtonItems 内のカスタム ビューを使用して目的の動作を取得することです。

サブクラス化が必要な何をしようとしていますか?

また、IB が実際にナビゲーション バーを置き換えているとは思いません。デフォルトのものを表示していないだけで、カスタムナビゲーションバーをサブビューとして持っていると確信しています。UINavigationController.navigationBar を呼び出すと、バーのインスタンスが取得されますか?

于 2009-12-08T19:45:34.927 に答える
0

背景画像を変更するためだけに navBar をサブクラス化したい場合 - iOS 5 では必要ありません。このsetBackgroundImageのようなメソッドがあります。

于 2011-08-09T13:41:57.850 に答える
0

obb64のコメントに加えて、私は彼のトリックを使用してsetViewControllers:animated:、コントローラーをペン先からロードされたものとして設定することになりrootControllerました。navigationController私が使用しているコードは次のとおりです。

- (void) presentModalViewControllerForClass: (Class) a_class {
  UINavigationController *navController = [[[NSBundle mainBundle] loadNibNamed: @"CustomNavBar" owner:self options:nil] lastObject];

  LoginSignupBaseViewController *controller = [[a_class alloc] initWithNibName: nil bundle: nil];
  controller.navigationController = navController;
  [navController setViewControllers: A(controller) animated: NO];

  [self presentModalViewController: navController animated: YES];

  [controller release];
}
于 2011-02-02T23:15:13.343 に答える