☆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
以降の説明で、
プロパティの属性は以下の通り。
W | readwrite;getter/setterが生成される |
R | readonly(読み取り専用) |
G= | getter名は指定通り |
T | retain属性(保持) |
C | copy属性(深いコピー) |
S | assign属性(参照のみ) |
A | atomic |
指定がないプロパティは読み書き可能のnonatomicである。
なんか最近はstrongなる属性もあるらしいが、使ったことないので知らない。
プロパティもしくはメソッドで設定可能な属性は、InterfaceBuilder(以下IB)でも「ほとんど」設定出来る。
なので、それらについては基本的に説明しない。
IB上の表記とプロパティ名は微妙に名前が異なったりするので、それぞれの対応を表にすれば便利だろうが、あまりに膨大な量なので省略。
見比べれば何とか判るはず。逆に、プロパティもしくはメソッドの説明では判らない部分もIBで実際にレイアウトして使ってみれば判ることも多い。
IBは慣れればプログラム側にかかる負荷がかなり軽減されるので、慣れた方が良い。
UIViewController
UIViewControllerは、画面表示について、最も総括的に制御するコントローラーである。
メソッドには、実装すべきプロトコルも含む。
UIViewController
メソッド名 | 動作 |
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle | nibファイルとバンドルを指定してインスタンスを初期化する
バンドルは通常[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 *navigationController | RT | 親のナビゲーションコントローラを返す。ないならnilを返す |
UINavigationItem *navigationItem | RT | ナビゲーションバーで表示を設定するためのアイテムを返す |
UITabBarController *tabBarController | RT | 親のタブバーコントローラを返す。ないならnilを返す |
UIModalTransitionStyle modalTransitionStyle | S | モーダルでビュー・コントローラを表示するときの移行スタイルを指定する
UIModalTransitionStyle(enum値)
定数名 | ビュー選択時動作 | ビュー解除時動作 | 補足 |
UIModalTransitionStyleCoverVertical | 下から上へ | 上から下へ | デフォルト |
UIModalTransitionStyleFlipHorizontal | 右から左へ3D(前のビューの裏側) | 左から右へ | iBookのページ送り |
UIModalTransitionStyleCrossDissolve | 前のビューが徐々に消え次のビューが徐々に見える | クロスフェード | ? |
UIModalTransitionStylePartialCurl | 下からめくり上げる | その逆 | 親がフルクリーンでUIModalPresentationFullScreenを使う場合のみ有効 |
|
UISplitViewController *splitViewController | RT | 親または祖先の分割ビュー・コントローラ |
CGSize contentSizeForViewInPopover | W | popoverのビューコントローラーのサイズ |
UIView
UIViewはウインドウ上に配置する全ての「ビュー=画面」に描かれる物の土台となるビューを作る。
その土台のことを「コンテント(内容)ビュー」と呼ぶ。クラス的に言えば「ルートビュー」である。
全ての土台となるため、非常に多くのプロパティとメソッドを持っている。
ビューを作る時は、座標と大きさをCGRect型で指定する。
作成したコンテントビューは、UIWindowのsetContentView:というメソッドを使って、ウインドウ内に設定する。
ビューは階層構造を取ることが出来る。
UIView
メソッド名 | 動作 |
-(id)initWithFrame:(CGRect)rect | CGRectで初期化する |
-(void)addSubview:(UIView *)view | このビュー上に他のビューを設定する |
-(void)removeFromSuperview | 親ビューからビューを外す(応答チェインも外す) |
-(void)bringSubviewToFront:(UIView *)view | 指定されたサブビューを前面へ動かす |
-(void)sendSubviewToBack:(UIView *)view | 指定されたサブビューを背面へ動かす |
-(void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2 | index1と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
名称 | 型 | 動作 |
CGFloat | 型 | CG*で使う浮動小数点数値の型(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として保存することができない。
そういうときは、
- IBではUIViewControllerとして作成し、保存する。
- UIViewのクラスを作成する。
- その中に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)rect | CGRectで初期化する |
-(void)setRootViewController:(UIViewController *)rootView | ウインドウの上にルートになるビューコントローラーを設定する
通常はUINavigationController等が来る
iOS6ではaddSubviewは使えない。
|
-(void)makeKeyAndVisible | レシーバーをメインウインドウにして表示する |
-(void)makeKeyWindow | レシーバーをメインウインドウにする |
-(void)sendEvent:(UIEvent *)event | UIApplicationオブジェクトからレシーバーに送られるイベントを処理する |
プロパティ名 | 属性 | 動作 |
UIScreen *screen | T | カレント画面を設定/取得する |
UIWindowLevel windowLevel | | ウインドウレベルを設定/取得する
UIWindowLevel(CGFloat定数)
UIWindowLevelNormal | 通常 |
UIWindowLevelAlert | 警告alert view ビュー用 |
UIWindowLevelStatusBar | ステータスバー用 |
|
UIViewController *rootViewController | T | ルートビューコントローラーを返すまたは設定する
設定時は古いビューは全て取り除かれる |
BOOL keyWindow | RG=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> delegate | S | デリゲート指定 |
CGSize popoverContentSize | | 表示サイズ |
UIViewController *contentViewController | T | ポップオーバーを制御するビューコントローラーを設定する |
BOOL popoverVisible | RG=isPopoverVisible | ポップオーバーを表示するかどうか |
UIPopoverArrowDirection popoverArrowDirection | R | ポップオーバー矢印の方向を指定する
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> delegate | S | デリゲートを設定する |
NSArray *viewControllers | C | 管理するビューコントローラーを配列で与える |
デリゲートは
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つ前のビューに前に戻る。
ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの左側を更新する:
- 新しい最上位層ビューコントローラーがカスタムの左ボタンを持つときはそれを表示する
その指定には、ビュー・コントローラのナビゲーション・アイテムのleftBarButtonItemプロパティーを使う
- 新しい最上位層ビューコントローラーがカスタムの左ボタンを持たないが、1つ前のビューコントローラーが
backBarButtonItemプロパティーで有効なアイテムを設定しているなら、それを表示する
- カスタムのボタンが(上記のように)設定されてないなら、デフォルトの「戻る」ボタンが使われる。
そのタイトル文字列は1つ前のビューコントローラーのtitleプロパティーによって設定される。
(ただし、スタック上1つのビューコントローラーしかないときは「戻る」は表示されない)
ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの中央を更新する:
- 新しい最上位層ビューコントローラーがカスタムのtitleビューを持つときはそれを表示する
その指定には、ビュー・コントローラのナビゲーション・アイテムのtitleViewプロパティーを使う
- カスタムのボタンが設定されてないなら、デフォルトのtitleが使われる。
そのラベル文字列はビューコントローラーそのもののtitleプロパティーが持っている。
他のタイトルを表示したいならビューコントローラーのtitleプロパティーに設定する
ナビゲーション・コントローラは、以下の通りにナビゲーション・バーの右側を更新する:
- 新しい最上位層ビューコントローラーがカスタムの右ボタンを持つときはそれを表示する
その指定には、ビュー・コントローラのナビゲーション・アイテムのrightBarButtonItemプロパティーを使う
- カスタムのボタンがないときは、何も表示しない
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> delegate | S | デリゲートを設定する |
UIViewController *visibleViewController | RT | 表示中のビューコントローラーを返す |
UINavigationBar *navigationBar | R | ナビゲーションコントロールで管理されているナビゲーションバーを返す |
UIToolbar *toolbar | R | ナビゲーションコントローラで管理されているツールバーを返す |
BOOL navigationBarHidden | G=isNavigationBarHidden | ナビゲーションバーを隠す |
BOOL toolbarHidden | G=isToolbarHidden | ツールバーを隠す |
UIViewController *topViewController | RT | ナビゲーションスタックの一番上のビューコントローラー |
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> delegate | S | デリゲートを設定する |
UIBarStyle barStyle | S | バーの形状を指定する |
UIColor *tintColor | T | バーの色 |
BOOL translucent | SG=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