☆Cocoa Touch UIKit勉強(1)
UIKitクラス階層構造
UIKitのビューとコントロールのクラス継承構造は、以下のようになっている。 個々のクラス説明ではほとんど記述していないが、親クラスのメソッドやプロパティは全て子クラスでも使える。
NSObject
 +---UIResponder---UIView--+---UIWindow
 |     |                   +---UILabel
 |     |                   +---UIPickerView
 |     |                   +---UIActivityIndicatorView
 |     |                   +---UIProgressView
 |     |                   +---UIImageView
 |     |                   +---UINavigationBar
 |     |                   +---UITabBar
 |     |                   +---UIToolBar
 |     |                   +---UIAlertView
 |     |                   +---UIActionSheet
 |     |                   +---UIScrollView----+---UITableView
 |     |                   |                   +---UITextView
 |     |                   +---UITableViewCell
 |     |                   +---UISearchBar
 |     |                   +---UIWebView
 |     |                   +---UIControl   ----+---UIButton
 |     |                                       +---UISwitch
 |     |                                       +---UISegmentedControl
 |     |                                       +---UISlider
 |     |                                       +---UITextField
 |     |                                       +---UIDatePicker
 |     |                                       +---UIPageControl
 |     |
 |     +----UIViewControl-------UISplitViewController
 |     |           +----UITabBarController
 |     |           +----UITableViewController
 |     |           +----UINavigationController
 |     |                   +----UIImagePickerController
 |     +----UIApplication
 |
 +---UIImage
 +---UIPopoverController
 +---UILocalNotification
 +---UIDevice
 +---UIScreen
 +---UIFont
 +---UIColor
 +---UIAccelerometer
 +---UIAcceleration

以降の説明で、 プロパティの属性は以下の通り。
Wreadwrite;getter/setterが生成される
Rreadonly(読み取り専用)
G=getter名は指定通り
Tretain属性(保持)
Ccopy属性(深いコピー)
Sassign属性(参照のみ)
Aatomic
指定がないプロパティは読み書き可能のnonatomicである。
なんか最近はstrongなる属性もあるらしいが、使ったことないので知らない。

プロパティもしくはメソッドで設定可能な属性は、InterfaceBuilder(以下IB)でも「ほとんど」設定出来る。 なので、それらについては基本的に説明しない。 IB上の表記とプロパティ名は微妙に名前が異なったりするので、それぞれの対応を表にすれば便利だろうが、あまりに膨大な量なので省略。 見比べれば何とか判るはず。逆に、プロパティもしくはメソッドの説明では判らない部分もIBで実際にレイアウトして使ってみれば判ることも多い。 IBは慣れればプログラム側にかかる負荷がかなり軽減されるので、慣れた方が良い。
UIViewController
UIViewControllerは、画面表示について、最も総括的に制御するコントローラーである。 メソッドには、実装すべきプロトコルも含む。
UIViewController
メソッド名動作
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundlenibファイルとバンドルを指定してインスタンスを初期化する
バンドルは通常[NSBundle mainBundle]
-(void)viewDidLoadビューの読み込みが終了した時に呼び出される
-(BOOL)isViewLoadedビューがメモリ上に読み込まれているかどうか
-(void)viewWillAppear:ビューが描画される前やアニメーションが始まる前に呼び出される
-(void)viewDidAppear:ビューが最後まで描画された後やアニメーションが終了した後に呼び出される
-(void)viewWillDisappear:ビューが非表示にされる前や解放される前に呼び出される
-(void)viewDidDisappear:ビューが非表示にされたり解放された時に呼び出される
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation ビューが指定方向の回転をサポートするかを返す。以下のenum値のORで指定する。
指定されてない方向には回転しない。
UIInterfaceOrientation(enum値)
UIInterfaceOrientationPortraitポートレイト方向(ホームボタンが下)
UIInterfaceOrientationPortraitUpsideDownポートレイト方向(ホームボタンが上)
UIInterfaceOrientationLandscapeLeftランドスケープ方向(ホームボタンが右)=UIDeviceOrientationLandscapeRightなので注意
UIInterfaceOrientationLandscapeRightランドスケープ方向(ホームボタンが左)=UIDeviceOrientationLandscapeLeftなので注意
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
 duration:(NSTimeInterval)duration
ユーザインタフェースの回転を始める前に呼び出される
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
 duration:(NSTimeInterval)duration
ユーザインタフェースの回転を始める前に呼び出される(アニメーション付き)
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation ユーザインタフェースが回転した後呼び出される
-(void)didReceiveMemoryWarningアプリケーションがメモリ不足の警告を発した時呼び出される
-(void)presentViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(void (^)(void)comletion 表示するビューコントローラを設定する
iOS5からはpresentModalViewControllerは使えない。
-(void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void)comletion レシーバのモーダルビューコントローラを解放する
iOS5からはdismissModalViewControllerAnimatedは使えない。

プロパティ名属性内容
UIView *view Tコントローラの管理するビューを指定する
NSString *title Cコントローラの管理するビューのタイトルを指定する
UIInterfaceOrientation interfaceOrientation Rインタフェースの現在の向きを返す
UIViewController *parentViewController R親のビューコントローラを返すないならnilを返す
UINavigationController *navigationControllerRT親のナビゲーションコントローラを返す。ないならnilを返す
UINavigationItem *navigationItem RTナビゲーションバーで表示を設定するためのアイテムを返す
UITabBarController *tabBarController RT親のタブバーコントローラを返す。ないならnilを返す
UIModalTransitionStyle modalTransitionStyle Sモーダルでビュー・コントローラを表示するときの移行スタイルを指定する
UIModalTransitionStyle(enum値)
定数名ビュー選択時動作ビュー解除時動作補足
UIModalTransitionStyleCoverVertical下から上へ上から下へデフォルト
UIModalTransitionStyleFlipHorizontal右から左へ3D(前のビューの裏側)左から右へiBookのページ送り
UIModalTransitionStyleCrossDissolve前のビューが徐々に消え次のビューが徐々に見えるクロスフェード?
UIModalTransitionStylePartialCurl下からめくり上げるその逆親がフルクリーンでUIModalPresentationFullScreenを使う場合のみ有効
UISplitViewController *splitViewControllerRT親または祖先の分割ビュー・コントローラ
CGSize contentSizeForViewInPopoverWpopoverのビューコントローラーのサイズ


UIView
UIViewはウインドウ上に配置する全ての「ビュー=画面」に描かれる物の土台となるビューを作る。 その土台のことを「コンテント(内容)ビュー」と呼ぶ。クラス的に言えば「ルートビュー」である。 全ての土台となるため、非常に多くのプロパティとメソッドを持っている。

ビューを作る時は、座標と大きさをCGRect型で指定する。 作成したコンテントビューは、UIWindowのsetContentView:というメソッドを使って、ウインドウ内に設定する。 ビューは階層構造を取ることが出来る。

UIView
メソッド名動作
-(id)initWithFrame:(CGRect)rectCGRectで初期化する
-(void)addSubview:(UIView *)viewこのビュー上に他のビューを設定する
-(void)removeFromSuperview親ビューからビューを外す(応答チェインも外す)
-(void)bringSubviewToFront:(UIView *)view指定されたサブビューを前面へ動かす
-(void)sendSubviewToBack:(UIView *)view指定されたサブビューを背面へ動かす
-(void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2index1と2のサブビューを交換する
-(void)insertSubview:(UIView *)view
aboveSubview:(UIView *)siblingSubview
belowSubview:(UIView *)siblingSubview
atIndex:(NSInteger)index

ビュー階層で他のビューより1段上のビューに追加する
ビュー階層で他のビューより1段下のビューに追加する
ビュー階層で指定番号のビューを追加する
-(UIView *)viewWithTag:(NSInteger)tag指定されたタグを持つビューを返す
-(void)setNeedsDisplayビュー全体を再描画する必要があることをシステムに通知する
-(void)setNeedsDisplayInRect:(CGRect)invalidRectビューの一部を再描画する必要があることをシステムに通知する
-(void)drawRect:(CGRect)rectビュー内を描画する時に呼び出される。描画対象はrect内。
setNeedsDisplay/setNeedsDisplayInRectを呼び出すとOS経由でこれが呼び出される。 これを直接呼び出してはいけない。
-(BOOL)endEditing:(BOOL)forceテキストフィールドの第一応答者(first responder)状態を解除する
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event指定されたタッチポイントを含む表示階層(自身を含む)で、レシーバーの一番遠い子孫を返す
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)eventタッチイベントがそのビューで発生したかどうかを判断する
-(void)removeGestureRecognizer:(UIGestureRecognizer *)gestureRecognizerジェスチャー認識を解除する
-(CGSize)sizeThatFits:(CGSize)sizeサブビューに対して最適なサイズを計算して返す
-(void)sizeToFit描画対象の大きさに合わせてビューのサイズを調整する

プロパティ名属性動作
UIColor *backgroundColor C背景色を設定する
CGRect frame  絶対座標で位置とサイズを指定する
CGRect bounds  親View内での相対座標で位置とサイズを指定する
CGPoint center  Viewの中央座標を指定する
NSArray *gestureRecognizers Cビューに接続されたジェスチャー認識オブジェクトを取得する
NSArray *subviews RCサブビューを取得する
UIView *superview R親ビューを取得する。親がなければnil

ウインドウやビューの座標や幅設定にはCG*構造体および関数を使う。
CGGeometry.h /GBase.h
名称動作
CGFloatCG*で使う浮動小数点数値の型(bit数は環境によって異なる)
CGRect構造体オブジェクトの左上座標とそこからの幅を持つ
C構造体オブジェクトの中央座標を持つ
CGSize構造体オブジェクトの幅を持つ
CGRectMake(x,y,幅,高さ)関数CGRect型を返す
CGPointZero構造体定数原点座標を示す

CGGeometry Reference

実際の構造体の定義は以下の通り。これらは(クラスではなく)構造体なので、NSLog()で表示するときは"%@"では表示出来ない。
表示するときは各メンバーに対して"%f"を使う。

struct CGPoint {
   CGFloat x;
   CGFloat y;
};
struct CGSize {
   CGFloat width;
   CGFloat height;
};
struct CGRect {
   CGPoint origin;  // frame.origin.x   frame.origin.y
   CGSize size;     // frame.size.width frame.size.height
};

 UIviewは土台となり、部品として使い回したいにもかかわらず、IB上ではUIViewとして保存することができない。 そういうときは、
  1. IBではUIViewControllerとして作成し、保存する。
  2. UIViewのクラスを作成する。
  3. その中にawakeFromNibメソッドを実装してnibを読み込む。
という手順をとる。
- (void)awakeFromNib
// xibからUIViewを読み込む処理
{
    [[NSBundle mainBundle] loadNibNamed:@"nibファイル名" owner:self options:nil]; // 拡張子(.xib)は不要
    [self addSubview:editorView];

    // ここが呼び出されるのはこのUIViewを読み込むUIViewControllerのviewDidLoadが終了した後である。
    // したがって、それ以前では内容が不定なので、nibからloadされる項目についての設定を行なってはいけない
    // ここからにviewDidLoad相当を記述する
    NSLog(@"viewDidLoad相当:self=%@",self);
    ~
}

UIViewの上に各種UI要素をレイアウトして表示を作ることが多いが、 QuickDraw関数;CG*()を使ってもっと細かく描画することもできる。 直線、円弧、多角形を始め、非常に多くの描画関数が用意されている。 それによる描画は基本的にdrawInRect:に記述するが、他の方法もある。 それについては別の機会に。


UIWindow
ユーザインタフェースの作成にはまず、ウインドウを作る。iPad/iPhoneアプリでは基本的にウインドウはフル画面の1つだけである。
UIWindowがウインドウのためのクラスである。基本的には、initWithFrame:メソッドを呼べばウインドウが出来上がる。
実は、initWithFrameはUIWindow独自のメソッドではない(そこで探しても見つからない)。UIWindowは前述の UIViewの子クラスであるため、そのメソッドが使えるのである。
UIWindow
メソッド名動作
-(id)initWithFrame:(CGRect)rectCGRectで初期化する
-(void)setRootViewController:(UIViewController *)rootViewウインドウの上にルートになるビューコントローラーを設定する
通常はUINavigationController等が来る
iOS6ではaddSubviewは使えない。
-(void)makeKeyAndVisibleレシーバーをメインウインドウにして表示する
-(void)makeKeyWindowレシーバーをメインウインドウにする
-(void)sendEvent:(UIEvent *)eventUIApplicationオブジェクトからレシーバーに送られるイベントを処理する

プロパティ名属性動作
UIScreen *screenTカレント画面を設定/取得する
UIWindowLevel windowLevel ウインドウレベルを設定/取得する
UIWindowLevel(CGFloat定数)
UIWindowLevelNormal 通常
UIWindowLevelAlert 警告alert view ビュー用
UIWindowLevelStatusBar ステータスバー用
UIViewController *rootViewControllerTルートビューコントローラーを返すまたは設定する
設定時は古いビューは全て取り除かれる
BOOL keyWindowRG=isKeyWindowレシーバーがアプリにとって重要なウインドウ(キーウインドウ=メインウインドウ)であるか示す


UIImageView
UIImageViewは画像を表示を制御するクラスである。1枚の画像の管理そのものは後述の UIImageView
メソッド名動作
-(id)initWithImage:(UIImage *)image表示する画像を設定する
-(id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage通常表示と強調表示表示する画像を設定する
-(void)startAnimatingアニメーションを開始させる
-(void)stopAnimatingアニメーションを停止させる
-(BOOL)isAnimatingアニメーションが開始しているかどうかを取得する

プロパティ名属性動作
UIImage image T表示する画像を設定する
NSArray *animationImages Cアニメーションのコマ画像を配列で設定する
NSInteger animationRepeatCount アニメーションのリピート回数を設定する
NSTimeInterval animationDuration  アニメーションの1コマが切り替わる時間を設定する
BOOL highlighted G=isHighlighted強調表示にする
NSTimeInterval animationDuration  1秒あたりの表示枚数を設定する

// 画像表示
UIImage     *img = [UIImage imageNamed:@"hoge.png"];
UIImageView *iv  = [[[UIImageView alloc] initWithImage:img] autorelease];
[self.view addSubview:iv];

// アニメーション表示
UIImage *im1 = [UIImage imageNamed:@"img1.png"];
UIImage *im2 = [UIImage imageNamed:@"img2.png"];
UIImage *im3 = [UIImage imageNamed:@"img3.png"];
NSArray *ims = [NSArray arrayWithObjects:im1, im2, im3, nil]; // コマ順指定
iv.animationImages   = ims;
iv.animationDuration = 1.5;
[iv startAnimating]; // アニメーション開始
[iv stopAnimating ]; // アニメーション停止

UIPopoverController
ポップオーバーはiPadのみのビューである。
これは、iPadの大画面を活かし、画面の中にポップアップで子画面を開くことができる。
iPad/iPhoneのユニバーサルアプリを作るときは、iPnoneではモーダルビューで切り替えていた画面をiPadではポップオーバーで 開くするように実装すると、画面サイズが同じにできるので(比較的)楽である。
ただし1つ注意があって、モーダルビューは画面を閉じるのにはdismissViewControllerAnimated:メソッドの呼び出しが必須だが、 ポップオーバーは画面外をタッチすると自動的に閉じてしまう上に、困ったことにそれを検知する手段がないので、 設定画面のように、設定が確定される前に勝手に抜けるといけない画面では、 一時的にポップオーバーの自動閉じを禁止して、ボタン操作でdismissViewControllerAnimated:するように実装しなければならない。

 表示内容の設定は自体はUIViewControllerで行う。ということは、IBで作ったView構成を作り、それを割り付けることで 内容を生成出来るということである。 UIViewControllerのcontentSizeForViewInPopoverプロパティにデフォルト値を、 UIPopoverController.popoverContentSizeで個別設定する。 表示サイズはIBで設定しても変化しないので、プログラムで設定する必要がある(バグに近い仕様)。
ポップオーバーは、デバイスが回転されるときには一緒に回転される。 しかし、再回転すると落ちることがある。 現在の所、原因不明だが、問題が出るときには回転前にはdismissPopoverAnimated:して閉じておくのが無難であろう。
UIPopoverController
メソッド名動作
-(id)initWithContentViewController:(UIViewController *)viewControllerポップオーバーコントローラーを初期化する
-(void)setPopoverContentSize:(CGSize)size animated:(BOOL)animatedポップオーバーのサイズを変更する
-(void)setContentViewController:(UIViewController *)viewController animated:(BOOL)animated ポップオーバーの内容を変更する
-(void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated 指定されたボタン項目から飛び出たようにポップオーバーを表示する。
一番簡単な表示方法。
-(void)presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated 指定されたビューから飛び出たようにポップオーバーを表示する。
arrowDirectionsにUIPopoverArrowDirectionUnknownを指定してはいけない。
UIButtonから表示するときは、通常view=self.view、rect=UIButton.frameで良い。
-(void)dismissPopoverAnimated:(BOOL)animated プログラムからポップオーバーを消す
ポップオーバーを呼び出した側から強制的に消す場合に呼び出す。

プロパティ名属性内容
id <UIPopoverControllerDelegate> delegateSデリゲート指定
CGSize popoverContentSize  表示サイズ
UIViewController *contentViewController Tポップオーバーを制御するビューコントローラーを設定する
BOOL popoverVisibleRG=isPopoverVisibleポップオーバーを表示するかどうか
UIPopoverArrowDirection popoverArrowDirectionRポップオーバー矢印の方向を指定する
UIPopoverArrowDirection(enum値)
UIPopoverArrowDirectionUp上向き
UIPopoverArrowDirectionDown下向き
UIPopoverArrowDirectionLeft左向き
UIPopoverArrowDirectionRight右向き
UIPopoverArrowDirectionAny全方向
UIPopoverArrowDirectionUnknown方向不明

デリゲートは UIPopoverControllerDelegate プロトコルを準拠する。
メソッド名動作
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController (自動的に)閉じるときに呼び出される。dismissPopoverAnimated:発行時には呼び出されない。
-(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController 自動的にポップオーバーを閉じて良いかどうかを指定する


分割表示;UISplitViewController
UISplitViewControllerはiPadのみのコントローラーで、その広い画面を活かした分割画面表示を行う。
UISplitViewControllerクラスは、2つの並んでいるビューコントローラの表示を管理する。 通常左側のビューコントローラーはアイテムのリストを表示し、 右側は選択されたアイテムの詳細を表示する。

このクラスのインスタンスを作って初期化した後は、2つのビューコントローラをviewControllersプロパティーに 割り当てなければならない。UISplitViewControllerの主たる仕事は、 2つのビューコントローラーの表示を調整し、異なる配置の間の移行を管理することにある。
ランドスケープ(横)方向では、両方のビュー・コントローラが表示される。 ポートレイト(縦)方向では、詳細ビューコントローラーだけが表示される。 方向が変わるとき、UISplitViewControllerは隠れるビューコントローラーをポップオーバーで表示する。 この調整するためにデリゲートにメッセージを送る。

UISplitViewController
プロパティ名属性内容
id <UISplitViewControllerDelegate> delegateSデリゲートを設定する
NSArray *viewControllersC管理するビューコントローラーを配列で与える

デリゲートは UISplitViewControllerDelegateで実装する。
メソッド名動作
-(void)splitViewController:(UISplitViewController*)svc
popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController
隠れたビューコントローラをポップオーバーで表示するとき呼び出される
-(void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
指定されたビューコントローラが隠されるとき呼び出される
-(void)splitViewController:(UISplitViewController*)svc
willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)button
指定されたビューコントローラが再表示されるとき呼び出される


UINavigationController
UINavigationControllerは、階層的な画面遷移を管理する(特別な)コントロールである。 iPhoneではほぼ利用が必須となる。iPadでは、Popover内で使うことができる。 が、この両者での使い方は同じではない。そのあたりがちょいとややこしい。
[UINavigationController]
        ↓
    [UIViewController]:ルート画面(第1階層)
                →[UIViewController]:子画面(第2階層)
                            →[UIViewController]:子画面(第3階層)
                                    ...

このクラスは、子クラスになることが出来ない。 各階層はビューコントローラーで管理する。

上の図で、最初の画面はユーザーに選択可能なアプリケーションのリストを表示する(左)。 アプリケーションを選択すると、それぞれの設定とアプリケーションの設定グループを表示する(中央)。 UINavigationControllerは、ルートビュー以外にはユーザーが上の階層に戻るための(Back)ボタンを提供する。

ナビゲーションコントローラーオブジェクトは、ナビゲーションスタックを用いて現在表示している画面を管理する。 スタックなので、一番下(底)はルートビューである。 スタック制御のためにはメソッドを利用する。最もよく使うのは、pushViewController:animated:メソッド(後述)で 新しい画面をスタックに積むことである。それは、ビューの表示とナビゲーションコントロールに更新を反映させる。 一般的に、情報階層で次の階層につながる項目を選んだ物を積む。 popViewControllerAnimated:メソッドでスタックから取り出すことも出来るが、 ナビゲーションコントロールは、戻るボタンを(必要に応じて)提供する。

UINavigationControllerはUIViewControllerからクラスを受け継ぐので、 ビューのプロパティを通じてアクセスできる。 ナビゲーションインターフェースを配置するとき、必ずルートビューを作らなくてはならない。 例えば、ナビゲーションインターフェースを自身によって配置するとき、ウインドウのメインのサブビューを作ることになる。 ナビゲーションインターフェースをタブバーの内側に組み込むためには、 適当なタブのルートビューにナビゲーションコントロールを組み込む。

ナビゲーションコントローラのビューは、 ちょうどカスタムの内容を含んでいるナビゲーションバー、オプションのツールバーとビューを含むいくつかの他のビューのための コンテナ(入れ物)である。 下図は、これらのビューがどのように集まってナビゲーションインターフェースを構築しているかを示している。

ナビゲーションバーとツールバービューの内容は変わるが、ビュー自体は変わらない。 カスタムのコンテントビューだけは、ナビゲーションスタックの最上位であるビューコントローラを反映するために変わる。
注: カスタムビューが利用できるスペースの量は可変なので、カスタムビューのautoresizingMaskプロパティは、柔軟な幅と高さをもっていなければならない。
ビューを表示する前に、ナビゲーションコントローラは、利用できるスペースに合わせるために、 自動的に大きさを設定する。 ナビゲーションコントローラは、ナビゲーションバーとナビゲーションツールバーの構成と表示を管理する。 これらのビューを直接修正してはならない。 代わりに、メソッドとUINavigationControllerクラスのプロパティを通してそれらを操作する。 navigationBarHiddenプロパティーまたはsetNavigationBarHidden:メソッドを使ってナビゲーションバーを表示したり隠したり出来る。

ナビゲーションバーのカスタムアイテムを指定するために、 後述の「Navigation Barを更新する」に定めるとおりにビュー・コントローラを構成する。 ナビゲーションツールバーにアイテムを指定する方法については、後述の「Toolbarを表示する」を参照のこと。 直接ナビゲーション・バー・オブジェクトを修正するべきでない。 数少ない例外として、ナビゲーションバーのbarStyleまたはtranslucent(半透明)プロパティーは修正出来るが、 frame、bounds、alpha値は変更出来ない。

 また、ナビゲーションコントローラオブジェクトは、ナビゲーションスタックの上で 動的にビューコントローラと関連したナビゲーションアイテム( UINavigationItemクラスのインスタンス)を使っている ナビゲーションバーの内容を造る。 ナビゲーションバーの内容を変えるために、カスタムビューコントローラのためにナビゲーションアイテムを構成しなければならない。

「Navigation Barを更新する」
ユーザーが、スタックにプッシュする・ポップするまたは直接スタックを操作することで最上位層のビュー・コントローラを変えるとき、 ナビゲーションコントローラは、それに従ってナビゲーション・バーを更新する。 具体的には、ナビゲーション・コントローラは、左・中央・右の3カ所に表示されるバーのボタンアイテムを更新する。 バー・ボタン・アイテムは、UIBarButtonItemのインスタンスである。 必要に応じて、カスタムの内容または標準的なシステム・アイテムを作製することができる。

ナビゲーションバーの左側のバーボタンアイテムは、ナビゲーションスタック上で1つ前のビューに前に戻る。

ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの左側を更新する: ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの中央を更新する: ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの右側を更新する: top view controllerが変更されるたびに、ナビゲーションコントロールはナビゲーションバーを更新する。 このように、ビュー・コントローラがスタックのプッシュ・ポップされるたびに、これらの変化が起こる。 アニメーション指定も出来る。

「Toolbarを表示する」
ナビゲーション・コントローラ・オブジェクトは、カスタムのツールバーをナビゲーション・インターフェースの 各々の画面に提供することを簡単にする。 ナビゲーション・コントローラ・オブジェクトは、現在そのビュー階層でオプションのツールバーを管理する。 それが表示されるとき、このツールバーはアクティブ・ビュー・コントローラの toolbarItemsプロパティーからアイテムの設定を得る。 アクティブ・ビュー・コントローラが変わるとき、ナビゲーション・コントローラは新しいビュー・コントローラに 合わせるためにツールバー・アイテムを更新する(アニメーション付き)。
ナビゲーション・ツールバーは、デフォルトでは隠される、 setToolbarHidden:animated:メソッドによって表示できる。 ビューコントローラーの全てがツールバーアイテムをサポートするのではないのなら、 以後のプッシュ・ポップにおいてツールバーの可視性を切り替えるために、デリゲートを呼び出す。

・・・と、いきなり仕様書を訳してみたが、たぶん使ってみるのが理解への早道である(^_^;)。

UINavigationController
メソッド名動作
-(id)initWithRootViewController:(UIViewController *)rootViewControllerナビゲーションコントロールを初期化する
-(NSArray *)popToRootViewControllerAnimated:(BOOL)animatedスタックをルートビューだけにする(表示も変更)
-(NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated指定したビューがスタック一番上に来るようにする
-(UIViewController *)popViewControllerAnimated:(BOOL)animatedスタックの一番上を取り出し、表示を更新する
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animatedスタックにビューコントローラーを積み、表示を更新する
-(void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated指定されたアイテムでナビゲーションコントローラで現在管理されているビューコントローラを置換する

プロパティ名属性内容
id <UINavigationControllerDelegate> delegateSデリゲートを設定する
UIViewController *visibleViewControllerRT表示中のビューコントローラーを返す
UINavigationBar *navigationBar Rナビゲーションコントロールで管理されているナビゲーションバーを返す
UIToolbar *toolbar Rナビゲーションコントローラで管理されているツールバーを返す
BOOL navigationBarHidden G=isNavigationBarHiddenナビゲーションバーを隠す
BOOL toolbarHidden G=isToolbarHiddenツールバーを隠す
UIViewController *topViewControllerRTナビゲーションスタックの一番上のビューコントローラー
NSArray *viewControllers Cナビゲーションスタック上のビューコントローラー配列

デリゲートは UINavigationControllerDelegate で実装する。
メソッド名動作
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
willShowViewController:(UIViewController *)viewController animated:(BOOL)animated

ナビゲーションコントロールがビューコントローラーとナビゲーションアイテムの属性を表示する前に呼び出す
ナビゲーションコントロールがビューコントローラーとナビゲーションアイテムの属性を表示した後に呼び出す
iOS6では画面の回転方法が変わったため、UINavigationViewをそのまま使ったのでは正しく画面回転しなくなった。 バグに近い仕様である。 詳しくは「うたブログ~情報編」に「iOS6対応の仕方」だったかで書いたので 参照のこと。


UINavigationBar/UINavigationItem
UINavigationBar/UINavigationItemは、対になってナビゲーションバーの上にUI要素を配置する。

UINavigationBarが下地となり、その上にUINavigationItemでアイテムを配置する。 実際、IBでUINavigationBarを配置するとItemも同時に入る(というか、UINavigationItemは直接配置出来ない)。

UINavigationBar
メソッド名動作
-void pushNavigationItem:(UINavigationItem *)item animated:BOOL animatedレシーバーのスタックから一番上の項目でPopしてナビゲーションバーを更新する。
-(UINavigationItem *)popNavigationItemAnimated:BOOL animatedレシーバーのスタック上にナビゲーション項目をPushして、ナビゲーションバーを更新する。
-void setItems:NSArray * items animated:BOOL animated項目を交換する

プロパティ名属性内容
id <UINavigationBarDelegate> delegateS デリゲートを設定する
UIBarStyle barStyleS バーの形状を指定する
UIColor *tintColorT バーの色
BOOL translucentSG=isTranslucentバーが透明かどうか指定する
NSArray *items C ナビゲーションバーの項目用配列を得る
UINavigationItem *topItem RTナビゲーションバーのスタックの最上位項目

UINavigationItem
メソッド名動作
-(id)initWithTitle:(NSString *)titleタイトル付きで初期化する
-(void)setHidesBackButton:(BOOL)hidesBackButton animated:(BOOL)animated戻るボタン設定
-(void)setLeftBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animatedバー更新時の左ボタン設定
-(void)setRightBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animatedバー更新時の右ボタン設定

プロパティ名属性内容
NSString *title Cナビゲーションバーの中央に表示する文字列
UIView *titleView Tこの項目が一番上の時、バーの中心に表示されるビュー
NSString *prompt Cナビゲーションバーの一番上で表示されるテキスト1行
BOOL hidesBackButton S戻るボタンを隠すかどうか
UIBarButtonItem *backBarButtonItem T戻るボタンの指定
UIBarButtonItem *leftBarButtonItem T左のボタンの指定
UIBarButtonItem *rightBarButtonItem T右のボタンの指定

UINavigationBarは、tintColorで色を変えられるが、背景に画像をはめ込むことも出来る。 この場合、UINavigationBarを継承したCustomNavigationBarクラスを作り、 Interface BuilderでUINavigationController内のUINavigationBarのクラスをこのCustomNavigationBarに変更すればいい。 もしくは、ナビゲーションバーが1つしかないなら、カテゴリで直接拡張しても良い。 この場合はIBでの変更も不要である。
@interface CustomNavigationBar : UINavigationBar
{
    UIImageView *backgroundView;
}
@end

@implementation CustomNavigationBar

- (void)setBackgroundImage:(UIImage *)image
{
    if (image == NULL) {
        return;
    }
    UIImageView *bgView = [[UIImageView alloc]initWithImage:image];
    backgroundView = bgView;
    [self addSubview:backgroundView];
    [self sendSubviewToBack:backgroundView];
    [bgView release];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self setBackgroundImage:[UIImage imageNamed:@"NavBarBackground.png"]];
    }
    return self;
}

- (void)pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated
{
    [super pushNavigationItem:item animated:animated];
    [self sendSubviewToBack:backgroundView];
}

- (UINavigationItem *)popNavigationItemAnimated:(BOOL)animated
{
    [super popNavigationItemAnimated:YES];
    [self  sendSubviewToBack:backgroundView];
    return [self topItem];
}

- (void)dealloc
{
    [backgroundView release];
    [super dealloc];
}
@end