結局、本の内容をなぞるだけの状態になっていて、
こんなのEvernoteにやっとけよ状態なのが心に痛い今日この頃です。
と言うわけで、今回読む章は…
6 テーブルのパターン
テーブルは、iPhoneでいちばんよく見かけるユーザーインタフェース。
便利で多機能だが、それゆえに複雑なプログラミングを要求される。
6.1 テーブルとは
6.1.1. テーブルはiPhoneの中心
テーブルビューの特性について書いてある。
6.1.2. UITableView と UITableViewCell
テーブル全体がUITableViewで、各行がUITableViewCell。 *01まあ、名前見れば想像はつく
ポイントは、UITableViewCellが、
Cocoa touchのビューの中では、ちと特殊であるということ。
一般的にCocoa touchのビューはサブクラス化を行わない。
理由は、挙動の制御や拡張はデリゲートで行うという思想から。
ただ、例外的にUITableViewCellは、サブクラス化されることを前提にしている。
6.1.3. テーブルのMVC
テーブルプログラミングのMVC構造について。
ビューがUITableViewとUITableViewCell。
コントローラがUIViewController。
モデルがモデルマネージャ。
ポイントは、UITableViewCellとインスタンスが1対1にならないこと。
理由はメモリの節約。
セルのインスタンスは最小限に抑え、使い回す。
よって、UITableViewCellは直接モデルと結びつけてはならず、
モデルマネージャを介してデータを取得する。
6.2 セルのパターン
6.2.1. 標準のセル
セルは様々にカスタム化して使用する。
その前に、標準のセルスタイル4つと右端に表示するアクセサリを紹介。
6.2.2. contentView と backgroundView
カスタムセルの作成について。
UITableViewCellのサブクラス構造を説明。
目的に応じて、どのサブクラスに手を入れるかを考える。
6.2.3. サブビューの作成
実際に、サブビューをカスタマイズして、RSSチャンネルの情報を表示するビューを作る。
1)UITableViewCellのサブクラスを作る。
名前はRSSCell。
インスタンス変数として宣言し、作成したサブビューへの参照を保持する。
@interface RSSChannelCell : UITableViewCell { // サブビュー UILabel* _titleLabel; UILabel* _feedLabel; UIImageView* _numberBackgroundImageView; UILabel* _numberLabel; } @end
↓
2)初期化メソッドを実装する。
initWithStyle:reuseIdentifier:を上書き。
その中でサブビューのインスタンス化を行う。
同時にcontentViewにaddSubView:を使ってビュー階層への追加も行う。
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier { // 親クラスの初期化メソッドを呼び出し self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if ( !self ) { return nil; } // title ラベルの作成 _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _titleLabel.font = [UIFont systemFontOfSize:16.0f]; _titleLabel.textColor = [UIColor blackColor]; _titleLabel.highlightedTextColor = [UIColor whiteColor]; [self.contentView addSubview:_titleLabel]; // feed ラベルの作成 _feedLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _feedLabel.font = [UIFont systemFontOfSize:12.0f]; _feedLabel.textColor = [UIColor grayColor]; _feedLabel.highlightedTextColor = [UIColor whiteColor]; [self.contentView addSubview:_feedLabel]; // UIImageView の作成 UIImage* image; image = [UIImage imageNamed:@"numberBackground.png"]; _numberBackgroundImageView = [[UIImageView alloc] initWithImage:image]; [self.contentView addSubView:_numberBackgroundImageView]; // 数字ラベル作成 _numberLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _numberLabel.font = [UIFont systemFontOfSize:17.0f]; _umberLabel.textColor = [UIColor whiteColor]; _numberLabel.backgroundColor = [UIColor clearColor]; _numberLabel.textAlignment = UITextAlignmentCenter; [self.contentView addSubview:_numberLabel]; return self;
サブビューのインスタンス化にはinitWithFrame:を使用。
この段階ではインスタンス化を行うのみで、領域サイズも0で構わない。
また、作成したインスタンスに対してautoreleaseを呼んでいない点にも注意。
これはdeallocで解放を行う。
6.2.4. コンテンツのためのアクセッサメソッド
作成したサブビューに値を設定するための、アクセッサメソッドを用意する。
方法は2つ。
1)追加したサブビューを、そのままプロパティとして提供する。
// サブビューのためのアクセッサ @property (nonatomic, readonly) UILabel* _titleLabel; @property (nonatomic, readonly) UILabel* _feedLabel;
実装は @synthesize を使ってプロパティメソッドを作成する。
// プロパティの実装 @synthesize titleLabel = _titleLabel; @synthesize feedLabel = _feedLabel;
利点は、コントローラ側で細かくサブビューの状態を制御できること。
欠点は、値を設定した際の再レイアウトを自前で行う必要があること。
2)コンテンツ自体を表すオブジェクトへのアクセッサを提供する。
// コンテンツのためのアクセッサ @property (nonatomic) int itemNumber;
実装はアクセッサメソッドを上書きして行う。
- (int)itemNumber { // ラベルから数値を取得 return [_numberLabel.text intValue]; } - (void)setItemNumber:(int)itemNumber { // ラベルにテキストを設定 _numberLabel.text = [NSString stringWithFormat:@"%d", itemNumber]; // セルの再レイアウト [self setNeedsLayout]; }
利点は、値を設定すると同時に再レイアウトを行えること。
欠点は、アクセッサメソッドの上書きをしてやる必要があること。
6.2.5. サブビューのレイアウト
作成したサブビューのレイアウトについて。
レイアウトはlayoutSubviewsメソッド内で行う。
初期化やアクセッサの中では行わない。
- (void)layoutSubviews { // 親クラスのlayoutSubviewsを呼び出す [super layoutSubviews]; // contentViewのサイズを取得 CGRect bounds; bounds = self.contentView.bounds; // titleLabelのレイアウト実行 ... // feedLabelのレイアウト実行 ...
6.2.6. セルのハイライト⁄選択
カスタマイズしたサブビューでの、ハイライトや選択状態表示について。
標準のセルは、既にこの機能を持っているので、
カスタマイズしたサブビューでも、これを上書きして使用する。
- (void)setHighlighted:(BOOL)highlighted animated:animated { // 親クラスのsetHighlighted:animatedを呼び出し [super setHighlighted:selected animated:animated]; // ラベルのハイライトを設定 _titleLabel.highlighted = highlighted; _feedLabel.highlighted = highlighted; } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { // 親クラスのsetSelected:animatedを呼び出す [super setSelected:selected animated:animated]; // ラベルのハイライトを設定 _titleLabel.highlighted = selected; _feedLabel.highlighted = selected; }
UILabelにはhighlightedプロパティがある。
これがYESになると、テキスト色にhighlightedTextColorが使用される。
【おまけ】GUI関係が出てくると気がはやる
テーブルとテーブルセル、このビューレイアウトは、
iPhoneアプリの大半で使われているものです。
このあたりの内容が出てくると、さすがに気がはやります。
現在、「読書と実践」の内で「読書」の部分しか、こなせていません。
「実践」が出来ていないのです。
本の内容に従って実際にRSSReaderを作成しつつ、
記事を書き進めるのがベストなのですが、
Xcode4へのバージョンアップなどもあり、
「実践」が追いついていません。
今は、「早く実際にコーディングしたい」という気持ちと、
「とにかく、ひと通り終わらせてしまいたい」と言う気持ちがせめぎ合い中。 *02あれ?昨日も同じ様なことを言っていた気が…
まあ、あと3章と少し。
何とか、行けるところまで頑張ってみましょうか。