前回は、画像(モデル)の削除と順序変更を実装してみました。続いて、テーブルビューに並んだ画像の名称変更を実現したいと思います。今回は、そのために必要となる新しいUIViewControllerの実装を解説します。
まず最初に、Interface Builder(v3.2.1)で画像情報の詳細(と言っても現在は名称だけ)を表示するためのUIViewControllerのnib(xib)ファイルを作成します。このビューコントローラの名称は「DetailViewController」とします。

ビュー上に、名称を入力するためのテキストフィールド(UITextField)を配置しただけの簡単な構成です。その左横にラベル(UILabel)で「名称」と表記しておきます。また、変更後の保存を実行するために、ナビゲーションバー上に配置する「保存」ボタン(UIBarButtonItem)もひとつ用意します。 ところで、UITextFieldは、数多くのアトリビュート(オプション)を持つコントロールのひとつです。こうしたアトリビュートはUITextField.hに定義されているプロパティと1対1で対応しています。以下の定義は、そのほんの一部です。
@property(nonatomic,copy) NSString *text; // 入力済み文字
@property(nonatomic,retain) UIColor *textColor; // 文字カラー
@property(nonatomic,retain) UIFont *font; // フォント種類とサイズ
こうしたプロパティに対してソースコードで値を代入すれば、アトリビュートを変更することができます。また、その初期値に関しては、Interface Builderのインスペクターウィンドウでも設定することができます。以下がインスペクターウィンドウで表示したUITextFieldクラスのアトリビュートです。

例えば、最初の「Text」アトリビュートは、先ほど示したNSStringのtextプロパティと一致しています。このカラムに文字列を入力しておけば、テキストフィールドが表示された時点で、その内容が代入されることになります。アトリビュートのタイトルを見れば、だいたいの設定内容は理解できるのですが、マウスカーソルをアトリビュート設定用コントロール上にしばらく静止させると、その説明がポップ表示されます(英語ですが...)。これを参考にすると良いでしょう。

ところが、これらのうち一番下の「Text Input Traits」タイトルで囲まれている7つのアトリビュートに関しては説明が表示されません。実は、これらはテキストフィールドのアトリビュートではなく(それが理由かどうかは定かではない)、UITextInputTraitsクラス(UITextInputTraits.h)に定義されている仮想キボードに対するアトリビュートなのです。以下が、7つのアトリビュートに対応する各プロパティの内容です。
@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
// 入力文字を自動で大文字に変換する作法を決める
@property(nonatomic) UITextAutocorrectionType autocorrectionType;
// 入力単語を自動で校正するかどうかを決める
@property(nonatomic) UIKeyboardType keyboardType;
// キーボードの種類を決める
@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
// キーボードアピアランスを決める(Alertはバックが黒色)
@property(nonatomic) UIReturnKeyType returnKeyType;
// リターンキーの表示文字内容を決める
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
// 文字入力がない時にリターンキーを使用可能にするかどうかを決める
@property(nonatomic,getter=isSecureTextEntry) BOOL secureTextEntry;
// パスワード入力モードにするかどうかを決める
例えば「Keybord」アトリビュートでは仮想キボードの種類を選ぶことができます。これを「Number Pad」と指定すれば、文字入力時にアルファベットキーボードの代わりにテンキーキーボードが表示されることになります。
実際のDetailViewController.h(クラス定義)は以下のような記述となります。Interface Builderでは、テキストフィールドと「保存」ボタンの両方を、ここに定義されているインスタンス変数(IBOutlet)へとリンクしておきます。
@class Model;
@interface DetailViewController : UIViewController <UITextFieldDelegate>
{
IBOutlet UIBarButtonItem *de_save; // 「保存」ボタン
IBOutlet UITextField *de_text; // テキストフィールド
Model *de_model; // 表示対象モデル(画像)
}
@property (nonatomic, retain) Model *de_model;
- (IBAction)saveName:(id)sender;
@end
このクラスは、文字入力でのリタンキーを制御するためのUITextFieldDelegateプロトコルにも準拠させます(次回に解説)。3つ目のインスタンス変数のde_modelは、詳細表示の対象となるモデルオブジェクト(Model)です。これは、RootViewControllerからDetailViewControllerを呼び出す時に渡されることになります。また、このクラスで定義されてるメソッドは「保存」ボタンをタップした時に実行されるsaveName:(アクションメソッド)ひとつだけです。
現状では、テーブルの行をタップすると、そこに登録されていた画像が表示されます。画像の名称を詳細ビューに表示させるためには、これとは別の方法を取る必要があります。そのため、行の右端に「アクセサリー」と呼ばれる小画像を表示させ、そこをタップすることで目的を達成します。 アクセサリーには以下の3種類あります。
typedef enum {
UITableViewCellAccessoryNone, // 表示なし
UITableViewCellAccessoryDisclosureIndicator, // (>)マーク
UITableViewCellAccessoryDetailDisclosureButton, // 詳細丸ボタン
UITableViewCellAccessoryCheckmark // チェックマーク
} UITableViewCellAccessoryType;
このうちUITableViewCellAccessoryDetailDisclosureButtonは青い丸ボタンを表示し、タップに反応してUITableViewのデリゲートを呼び出します。iPhone OS v2.xxでのアクセサリー表示はUITableViewのデリゲートで実現していましたが、この方法は、v3.xxから「DEPRECATED」(非推奨)となりました。代わりにセル(UITableViewCell)のプロパティであるaccessoryTypeへタイプ値を代入する方法が取られます。アプリの起動対象iPhone OSとしてv2.xxも考慮している方はご注意ください。
以前にRootViewController.hに実装した以下のデリゲートメソッドを少し修正し、アクセサリーの設定を追加します。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Model *model;
UITableViewCell *cell;
cell=[tableView dequeueReusableCellWithIdentifier:@"ImageCell"];
if( ! cell )
cell=[[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"ImageCell"] autorelease];
if( model=[rt_array objectAtIndex:indexPath.row] )
{
cell.textLabel.text=model.md_name;
cell.imageView.image=model.md_image;
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
// アクセサリー(青丸の詳細ボタン)の表示を指示する
}
return cell;
}
アクセサリーをタップすると、以下のUITableViewのデリゲートが呼ばれます。ここに詳細ビュー(UIDetailViewController)への切り替え処理を実装します。
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
{
Model *model;
SymmetryAppDelegate *app;
if( model=[rt_array objectAtIndex:indexPath.row] ) // 対象モデルを得る
{
app=[[UIApplication sharedApplication] delegate];
[app pushDetailViewControllerWithModel:model]; // 詳細ビューを表示
}
}
ビューコントローラをDetailViewControllerへと切り替える(プッシュする)メソッドはアプリケーションデリゲート(SymmetryAppDelegate.m)に実装します。また、作成したDetailViewControllerは、このクラスのap_detailvctrインスタンス変数へ保存します。加えて、表示を元に戻す(ポップする)メソッドもここに用意しておきます。
- (void)pushDetailViewControllerWithModel:(Model *)model
{
if( ! ap_detailvctr ) // 詳細ビューコントロラー用インスタンス変数
ap_detailvctr=[[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
if( ap_detailvctr )
{
ap_detailvctr.de_model=model; // 対象モデルを渡す
[navigationController pushViewController:(UIViewController *)ap_detailvctr animated:YES];
}
}
- (void)popViewController // ビューコントローラをポップする
{
[navigationController popViewControllerAnimated:YES];
}
今回は、詳細ビュー表示の下準備としてDetailController.m以外のソースコード部分を説明しました。次回は、引き続きDetailViewControllerクラス(DetailViewController.m)の実装を解説いたします。