Cells(1)~サブビューによるカスタマイズ

2010. 11. 04
テーブルビューのカスタマイズの手法として、セルにサブビューを追加する方法と、セルのサブクラスを追加する方法の2種類があります。

最初にサブビューを追加する方法を行います。

ここでは一つのセルに4つのラベルをサブビューとして追加してみます。

906

4つの内2つは固定の文字列で、残りの2つは固定文字列をキーとした値を辞書から取得して表示します。


●プロジェクトの作成

View-based Applicationテンプレートで、プロジェクト名を『Cells』とします。

903


●nibファイルの編集

nibファイルの編集は前回の『Simple Table(1)~テキストの表示』の時と同じです。

画面全体にテーブルビューを貼り付けます。

CellsViewController.xibをダブルクリックしてInterface Builderで開き、LibraryウィンドウからViewウィンドウへTable Viewをドラッグ&ドロップします。

878

UITableViewオブジェクトはデータソースとデリゲートを持つ必要があります。

今回はデータソースもデリゲートもビューコントローラ(CellsViewController)で行うので、InspectorウィンドウのConnectionsタブを開き、『Outlets』の『dataSource』と『delegate』をDocumentウィンドウのFile's Ownerに接続します。

879

接続が完了したら保存してXcodeに戻ります。


●ヘッダファイルの編集

CellsViewController.hを開き、デリゲート(UITableViewDelegate)とデータソース(UITableViewDataSource)プロトコルを導入し、データソースとなる配列witchesを宣言します。

配列や定数などの名前を変更していますが、コードの内容は同じです。
(太字が追加した部分)

#import <UIKit/UIKit.h>

#define kNameValueTag 1
#define kUnitValueTag 2


@interface CellsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
    NSArray *witches;
}

@property (nonatomic, retain) NSArray *witches;

@end

904


●ソースファイルの編集

CellsViewController.mを開き、配列witchesとデータソースメソッドの実装を行います。
(太字が追加・変更した部分)

#import "CellsViewController.h"

@implementation CellsViewController

@synthesize witches;

/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad {
    [super viewDidLoad];
    NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Yoshika Miyafuji",
    @"Name", @"A6M3a", @"Striker Unit", nil];
    NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Mio Sakamoto",
    @"Name", @"A6M3a", @"Striker Unit", nil];
    NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Minna-Dietlinde Wilcke",
    @"Name", @"Bf109G-2", @"Striker Unit", nil];
    NSDictionary *row4 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Lynette Bishop",
    @"Name", @"Spitfire Mk.IX", @"Striker Unit", nil];
    NSDictionary *row5 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Perrine-H.Clostermann",
    @"Name", @"VG39", @"Striker Unit", nil];
    NSDictionary *row6 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Erica Hartmann",
    @"Name", @"Bf109G-6", @"Striker Unit", nil];
    NSDictionary *row7 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Gertrud Barkhorn",
    @"Name", @"Fw190D-6", @"Striker Unit", nil];
    NSDictionary *row8 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Francesca Lucchini",
    @"Name", @"G-55 Centauro", @"Striker Unit", nil];
    NSDictionary *row9 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Charlotte E Yeager",
    @"Name", @"P-51D", @"Striker Unit", nil];
    NSDictionary *row10 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Eila Ilmatar Juutilainen",
    @"Name", @"Bf109G-2", @"Striker Unit", nil];
    NSDictionary *row11 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Sanya V.Litvyak",
    @"Name", @"MiG60", @"Striker Unit", nil];
    NSArray *array = [[NSArray alloc]initWithObjects:row1, row2, row3, row4, row5, row6, row7, row8, row9, row10, row11, nil];
    self.witches = array;
    [row1 release];
    [row2 release];
    [row3 release];
    [row4 release];
    [row5 release];
    [row6 release];
    [row7 release];
    [row8 release];
    [row9 release];
    [row10 release];
    [row11 release];
    [array release];

}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

    self.witches = nil;
    [super viewDidUnload];
}

- (void)dealloc {
    [witches release];
    [super dealloc];
}

#pragma mark -
#pragma mark Table Data Source Methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.witches count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellTableIdentifier = @"CellTableIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellTableIdentifier];

    if (cell == nil) {
        CGRect cellFrame = CGRectMake(0, 0, 300, 65);
        cell = [[[UITableViewCell alloc] initWithFrame:cellFrame reuseIdentifier:cellTableIdentifier] autorelease];

        CGRect nameLabelRect = CGRectMake(0, 5, 70, 15);
        UILabel *nameLabel = [[UILabel alloc] initWithFrame:nameLabelRect];
        nameLabel.textAlignment = UITextAlignmentRight;
        nameLabel.text = @"Name";
        nameLabel.font = [UIFont boldSystemFontOfSize:12];
        [cell.contentView addSubview:nameLabel];
        [nameLabel release];

        CGRect unitLabelRect = CGRectMake(0, 26, 70, 15);
        UILabel *unitLabel = [[UILabel alloc] initWithFrame:unitLabelRect];
        unitLabel.textAlignment = UITextAlignmentRight;
        unitLabel.text = @"Striker Unit";
        unitLabel.font = [UIFont boldSystemFontOfSize:12];
        [cell.contentView addSubview:unitLabel];
        [unitLabel release];

        CGRect nameValueRect = CGRectMake(80, 5, 200, 15);
        UILabel *nameValue = [[UILabel alloc] initWithFrame:nameValueRect];
        nameValue.tag = kNameValueTag;
        [cell.contentView addSubview:nameValue];
        [nameValue release];

        CGRect unitValueRect = CGRectMake(80, 25, 200, 15);
        UILabel *unitValue = [[UILabel alloc] initWithFrame:unitValueRect];
        unitValue.tag = kUnitValueTag;
        [cell.contentView addSubview:unitValue];
        [unitValue release];
    }

    NSUInteger row = [indexPath row];
    NSDictionary *rowData = [self.witches objectAtIndex:row];
    UILabel *name = (UILabel *)[cell.contentView viewWithTag:kNameValueTag];
    name.text = [rowData objectForKey:@"Name"];
    UILabel *unit = (UILabel *)[cell.contentView viewWithTag:kUnitValueTag];
    unit.text = [rowData objectForKey:@"Striker Unit"];
    return cell;
}


@end

905

shouldAutorotateToInterfaceOrientation:メソッド(アプリケーションで有効なデバイスの向きを指定)はコメントアウトを解除しています。
(特に追記はしていません)

・viewDidLoad

前回と異なり、スーパークラスによる初期化([super viewDidLoad];)が本書内およびApress社のサイト内のサンプルコードも入っていませんが、ここでは最初に入れたままにしておきます。

906

セルの内容は、『Name』と『Striker Unit』というキーとなる固定文字列と、行毎に異なる値となる文字列で、各行毎にinitWithObjectsAndKeys:メソッドで辞書を生成します。

ここでは11行分の辞書を生成し、initWithObjects:メソッドでarray配列にひとまとめにし、witches配列に入れた後、生成した辞書と配列を解放しています。

・viewDidUnload

今回は忘れずにwitche配列の所有権の放棄を追加しています。

・dealloc

witchesプロパティの解放を追記しています。

・tableView:numberOfRowsInSection:

テーブルビューの行数として、witches配列の要素数をcountメソッドで返しています。

・tableView:cellForRowAtIndexPath:

セル再利用時の識別子CellTableIdentifierを定義し、dequeueReusableCellWithIdentifier:メソッドで再利用可能なセルがあれば返す部分は前回と同じです。

if文内に記述されるセルの初回生成時の内容とその後で行っている共通部分が前回と異なります。

最初にCGRectMake関数でセルの矩形領域を決め、initWithFrame:reuseIdentifier:メソッドでセルを新規作成します。

次に4種の文字列を表示するサブビューを作ります。

(1)nameLabel(3)nameValue
(2)unitLabel(4)unitValue

CGRectMake関数でラベル用の矩形領域を設定し、initWithFrameメソッドでビューオブジェクトを作るところまでは共通です。

nameLabelとunitLabelは各行共通の固定文字列なので、textプロパティで文字列を、fontプロパティでスタイルとサイズを(ここではboldSystemFontOfSize:メソッドで太字の12ポイントに)設定します。

※2010.11.6追記
textAlignmentプロパティでラベルの右寄せ(UITextAlignmentRight)していることを書き忘れていましたので追記します。

UILabelオブジェクトとしての設定が済んだら、contentViewプロパティでセルをスーパービューとし、addSubview:メソッドでサブビューとして追加します。

nameValueとunitValueは各行で異なる文字列になりますので、if分内の初回生成では識別用にkNameValueTagとkUnitValueTag定数をtagプロパティで設定し、サブビューとして追加するのみで、各文字列の取得はif分の外で行っています。

各行固有の値は、まずインデックスパス(階層構造の配列に簡便にアクセスするためのパス)の行番号を取得し、objectAtIndex:メソッドでwitches配列から取得した当該行の内容をNSDictionaryのオブジェクトとして受け取ります。

if文内で設定したタグを元にviewWithTag:メソッドでセル内のビューを特定してUILabelのオブジェクトとし、objectForKey:メソッドで各サブビューの値を取得してtextプロパティで割り当てます。


initWithObjectsAndKeys:

- (id)initWithObjectsAndKeys:(id)firstObject , ...

指定したキーと値のセットからエントリを組み立てて、新規に割り当てた辞書を初期化します。

このメソッドはinitWithObjects:forKeys:に似ており、キーと値のペアで指定する点が異なっています。

例:

NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
    @"value1", @"key1", @"value2", @"key2", nil];

firstObject:新規辞書に追加する最初の値を指定します。

...:最初にfirstObjectのキーを指定子、以降は値とキーを交互にしたnull終端のリストになります。
キーがnilの場合、NSInvalidArgumentExceptionが発生します。


textAlignment

@property(nonatomic) UITextAlignment textAlignment

テキストの整列に使われる技術です。

このプロパティはテキスト文字列全体に適用されます。

このプロパティのデフォルト値はUITextAlignmentLeftです。


UITextAlignment

typedef enum {
    UITextAlignmentLeft,
    UITextAlignmentCenter,
    UITextAlignmentRight,
} UITextAlignment;

UITextAlignmentLeft
テキストを左端に揃えます。

UITextAlignmentCenter
テキストを中心線からの両端が等しくなるように揃えます。

UITextAlignmentRight
テキストを右端に揃えます。


contentView

@property(nonatomic, readonly, retain) UIView *contentView

セルオブジェクトのコンテントビューを返します。
(読み込みのみ)

UITableViewCellオブジェクトのコンテントビューは、セルに表示されるコンテンツのデフォルトのスーパービューです。

単純に追加ビューとしてカスタマイズしたセルを追加する場合は、編集モード以外でセルの中に適切に配置されるようにコンテントビューを追加する必要があります。


addSubview:

- (void)addSubview:(UIView *)view

姉妹より上に表示されるサブビューとして、レシーバにビューを追加します。

また、このメソッドはviewの次のレスポンダとして、レシーバを設定します。

レシーバはviewを保持します。

removeFromSuperviewを使ってビュー階層からviewを取り除く場合、viewは解放されます。

(例えばビューの数を介してスワップしている場合など)ビュー階層からviewを取り除いた後もviewを使い続ける場合は、removeFromSuperviewを呼び出す前にretainをしておく必要があります。

ビューはスーパービューを一つのみ持つことができます。

viewのスーパービューがnilではなく、現在のビューと同じではない場合、このメソッドは現在のビューのサブビューを作成する前に、以前のスーパービューから取り除きます。


tag

@property(nonatomic) NSInteger tag

レシーバのタグは、アプリケーション内のビューオブジェクトを識別するのに使う整数です。

デフォルト値は0です。

サブクラスは個々にタグを設定することができます。


ここで指定している領域ですが、原点座標はともかく、サイズが300x65ピクセルと少し疑問符が付くような指定になっています。
(1ピクセルの区切り線を除いたデフォルトの行高は43ピクセル)


viewWithTag:

- (UIView *)viewWithTag:(NSInteger)tag

指定したタグのビューを返します。

戻り値は、レシーバの階層でtagと一致するビューになります。

レシーバは検索対象に入ります。

tag:ビューの検索に使用するタグを指定します。



参考文献

NSDictionary Class Reference

UIView Class Reference

UITableViewCell Class Reference

UILabel Class Reference

NSString UIKit Additions Reference Class Reference

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る






Lifestyle 650 home entertainment system
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
10 | 2017/11 | 12
Sun Mon Tue Wed Thu Fri Sat
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

Lifestyle 650 home entertainment system
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR