momoto.github.io

iOS UITableViewをつかってリストを表現する

 iOS UITableViewをつかってリストを表現してみます。iOSは7.0.3、IDEにはXcode 5.0.2を使用しています。 この記事では、次のスクリーンショットのような簡単なアプリを動作させることを目的とします。

"iOS - libsqliteDemo スクリーンショット"

 まず、リストを表示させたい画面のView Controllerに、UITableViewのインスタンスを作成します。 インスタンスの作成には、ストーリーボードを使用する方法とView Controllerだけで記述する方法とがありますが、 ここではストーリーボードを使用する方法でインスタンスを作成していきます。

 ストーリーボードを使用する場合は、 (1) オブジェクトライブラリからTable Viewをえらんで、対象のシーン(View Controller)の中に追加 (2) 追加したTable Viewのオブジェクトを、View Controllerのアウトレットプロパティとして接続、までの操作をXcodeのGUIですすめていきます。 オブジェクトライブラリにはTable View Controllerというオブジェクトも用意されていますが、 既存のコントローラの中にTable Viewを組込むのであればTable View Controllerは使用しません(コントローラが増えてしまうので)。

 次に、View Controllerの定義部(.h)にうつって、View ControllerはUITableViewDataSourceプロトコルを採用するように、親クラス名の後に<UITableViewDataSource>を加えます。 また、ストーリーボードで接続したTable Viewがプロパティとして定義されているかどうかを確かめておきます。ここでは、TableViewオブジェクトのプロパティ名をtvとしました。

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDataSource>

@property (weak, nonatomic) IBOutlet UITableView *tv;

@end

 プロトコルの採用に伴って、View Controllerの実装部(.m)にはnumberOfRowsInSectioncellForRowAtIndexPathのふたつのメソッドの実装が必要になります。 このメソッドが実装されていない間は、Method 'メソッド名' in protocol not implementedというSemantic Issueが現れているはずなので、 ひとまず次のようにメソッドを実装して、viewDidLoadなどにはself.tv.dataSource = self;の1行を加えておきます。

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
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // Table ViewのデータソースにView Controller自身を設定する
    self.tv.dataSource = self;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Table Viewの行数を返す
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *tvcell = [tableView dequeueReusableCellWithIdentifier: @"cid"];
    if (tvcell == nil) {
        tvcell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                        reuseIdentifier: @"cid"];
    }
    // Table Viewの各行の情報を、UITableViewCellのオブジェクトとして返す
    tvcell.textLabel.text = [[NSString alloc] initWithFormat:@"%d行目のセル", indexPath.row + 1];
    return tvcell;
}

 この状態でビルドしてみると、5行のリストを表現できるようになりました。

 ここまでのコードを基に、セルの情報を配列に格納し、セルの挿入と削除ができるボタンを加えてみます。 再びストーリーボードに戻り、セル操作のイベントハンドラになるボタンをView Controllerに追加します。

 View Controllerの定義部では、セル情報を格納する配列cellsというプロパティを新たに定義します。

1
2
3
4
5
6
7
8
9
10
11
#import <UIKit/UIKit.h>

@interface SampleController : UIViewController <UITableViewDataSource>

@property (weak, nonatomic) IBOutlet UITableView *tv;
@property NSMutableArray *cells;

- (IBAction)insertCell:(id)sender;
- (IBAction)deleteAll:(id)sender;

@end

 View Controllerの実装部では、それぞれのメソッドを次のように変更します。 insertCelldeleteAllのメソッドでは、配列操作のあとに[selv.tv reloadData]でTable Viewをリロードするように指示しています。

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
- (void)viewDidLoad {
    [super viewDidLoad];
    self.cells = [NSMutableArray array];
    self.tv.dataSource = self;
}

- (IBAction)insertCell:(id)sender {
    [self.cells addObject: [[NSString alloc] initWithFormat:
                            @"%d行目のセル", [self.cells count] + 1]];
    [self.tv reloadData];
}

- (IBAction)deleteAll:(id)sender {
    self.cells = [NSMutableArray array];
    [self.tv reloadData];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *tvcell = [tableView dequeueReusableCellWithIdentifier: @"cid"];
    if (tvcell == nil) {
        tvcell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                        reuseIdentifier: @"cid"];
    }
    tvcell.textLabel.text = [self.cells objectAtIndex: indexPath.row];
    return tvcell;
}

 セル情報を配列に格納することで、アプリの中でセルの追加/削除を操作できるようになりました。

参考