2013年7月16日火曜日

UITableViewについて - UITableViewのセルをカスタムセルを使ったほうがいい(4)【追記あり】

まだまだいきます!今回もカスタムセルについてです。

今回は前回書いたものに、Xibファイルを使ったカスタムセルを実装してみます。

環境

  • Xcode : 4.6.2
  • iOS SDK : 6.1
  • デバッグ 実機 : iPod touch、バージョン6.1.3

目的

前回書いたものに、Xibファイルを使ってカスタムセルを実装する。
セルのコンテンツの重なりはないかと、セルの再利用が行われているかどうかを調べます。

作ってみる

それでは作っていきます。

今回は、

  • カスタムセルとしてUITableViewCellクラスを継承した「CustomCell」クラスを作成。
  • Xibファイルを使用する。new!!

Xibファイルは「CustomCell.xib」という名前で作成し、CustomCellクラスにリンクさせます。

プロジェクトの作成

プロジェクトは「Single View Application」で作成。

使用するクラス

  • ViewController.h/m - UIViewControllerクラス継承
  • CustomCell.h/m - UITableViewCellクラス継承
  • CustomCell.xib

ViewController

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

ViewController.h

#import "ViewController.h"
#import "CustomCell.h"

@interface ViewController () 
@property(nonatomic, retain)UITableView *tableView;  // テーブルビュー
@property(nonatomic, retain)NSArray *datas;  // 表示するデータを入れる配列
@end

@implementation ViewController

@synthesize tableView=_tableView;
@synthesize datas=_datas;

-(id)init
{
    if (self=[super init]) {
        // セルに表示するデータの初期化
        self.datas = [NSArray arrayWithObjects:@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j", nil];
    }
    
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // iOS 6.0以降からのセル再利用の設定(xibの場合)
    // http://blog.morizotter.com/2013/01/23/the-easiest-way-to-make-custamcell-with-xib/
    [self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellReuseIdentifier:@"CustomCell"];

    // テーブルビュー作成
    [self createTableView];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

#pragma mark -
#pragma mark - Private Method

// テーブルビュー作成
- (void)createTableView
{
    self.tableView = [[[UITableView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain] autorelease];
    self.tableView.dataSource = self;
    self.tableView.delegate = self;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
    [self.view addSubview:self.tableView];
}

#pragma mark -
#pragma mark - Table view delegate

// セルのセクション数を設定
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

// セルの個数を設定
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.datas count];
}

// セル高さを設定
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100;
}

// セルの内容を設定
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *CellIdentifier = @"CustomCell";
    
    CustomCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    if (cell == nil)
    {
        // initWithCustomeStyle:reuseIdentifier:labelData:メソッドで初期化と表示するデータの設定を行う
        cell = [[[CustomCell alloc] initWithCustomeStyle:UITableViewCellStyleDefault
                                                             reuseIdentifier:CellIdentifier
                                                                     labelData:[self.datas objectAtIndex:indexPath.row]] autorelease];
        NSLog(@"CustomCell init");
    }

    cell.label.text = [self.datas objectAtIndex:indexPath.row];
    
    return cell;
}

@end

CustomCell

CustomCell.h

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell
@property(retain, nonatomic)IBOutlet UILabel *label;
@end

CustomCell.m

#import "CustomCell.h"

@implementation CustomCell

@synthesize label=_label;

-(id)initWithCustomeStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier labelData:(NSString *)labeldata
{
    self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        self.label = [[UILabel alloc]initWithFrame:CGRectMake(120, 30, 150, 50)];
        self.label.text = labeldata;
        [self.contentView addSubview:self.label];

    }
    
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
}

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

@end

CustomCell.xib



CustomCell.xibでの設定を書きます。

  • Interface BuilderでUILabelを作成する。
  • 「Show the Identity inspector」の「Custom Class」に"CustomCell"を設定する。
  • 「Show the Attributes inspector」の「Identifier」に"CustomCell"を設定する。
  • CustomCell.hのIBOutletしたUILabelクラスをCustomCell.xibにリンクする。

結果

セルのコンテンツの重なりあり。
セルの再利用行われている。
セルの表示は前回と同じ。

おわり

Xibファイルを使ってもセルの表示は前回と同じでした。

それと、Xibファイルを使ってもIBOutletしたUIILabelなどをalloc/initする処理は必要なんですね。IBを使ったことがほとんどなかったのでこれは勉強になりました。当たり前のことだと思いますが(笑)

セルに乗っかるラベルなどのデータを入れるのはカスタムセルを呼ぶ側で指定した方がいいですね。


追記:2013/07/16 見てね!!
カスタムセル側でラベルなどのデータの値を設定すること自体間違っていました。

なぜかというと、もしセルの再利用が行われていればカスタムセルの初期化は行わない(initメソッドが動かない)ためinitメソッドの中に書いたラベルなどに対して行うデータの設定ももちろん実行されない。

だから、今回や前回の結果で、h, i, j が表示されず、変わりに前の表示で使った a, b, c が表示されたということになります。

ですがこれはきちんとセルの再利用がされているために起こったものであると考えられます。

セルごとにデータの値が変わる場合はセルを呼ぶ側で設定し、固定させたいものについてはカスタムセル側で設定する。

例えば、UILabelクラスをカスタムセルに表示する際、
セルを呼ぶ側では表示させるテキストの設定、カスタムセル側では alloc/init, frame, textColorなどを設定する。

書きなぐった感満載の分かりにくい説明になっちゃいました(笑)

参考記事

NibからCellを作って使いまわしてUITableViewCellを楽々カスタマイズ!- Morizotter Blog

0 件のコメント:

コメントを投稿