Interface Builderで作ったUI(xib)を別のxibで使い回す


iOSシミュレータのスクリーンショット 2013.08.03 13.44.20

Interface Builderで作った自作のView(xib)を、別のViewで使いたい、そんな事ってありますよね。
例えば上の画像だと、左側の画像とラベルの部品はUIKitには無いので自作する必要があるのですが、右側にラベルがくるセル、画像がくるセルで共通して使いたいわけです。

いつもハマるので書いておきます。

#import <Foundation/Foundation.h>

@interface LabelAndImageView : UIView
@property(nonatomic, strong) IBOutlet UIView *contentView;
@property(nonatomic, strong) IBOutlet UIImageView *imageView;
@property(nonatomic, strong) IBOutlet UILabel *label;
@end

LabelAndImageViewは、UIImageViewとUILabelをもつViewです。
contentViewはそれらを入れるビューですが、これが重要。
LabelAndImageView、こんな名前をつけてはいけません。

スクリーンショット 2013-08-03 13.56.57
Interface BuilderでLabelAndImageViewのUIを作ります。
Viewのデザインなので、サイズはNone、Status Barはいらない。

スクリーンショット 2013-08-03 13.57.20
File’s OwnerのクラスをLabelAndImageViewにして。

スクリーンショット 2013-08-03 13.57.45
File’s Ownerから各IBOutletに接続します。
contentViewのIBOutletは下敷きになっているViewと繋ぎます。
ここで終わりたくなりますが、もう一声。

- (void)awakeFromNib {
    [[NSBundle mainBundle] loadNibNamed:@"UserNameIconView" owner:self options:nil];
    [self addSubview:self.customContentView];
}

awakeFromNibメソッドでloadNibNamedして、addSubviewします。
Interface BuilderからLabelAndImageViewを呼び出したときに、対応するxibを探してロードすることができないのでしょうね。
そこは自分でやるしかない、と。
ハマりどころです。

あとは、他と難しいところはなく、Interface Builderを使っていない部品を使うのと一緒です。
迷える子羊がいるかもしれないから書いておきましょう。

@interface MyCell1 : UITableViewCell
@property(nonatomic, strong) IBOutlet LabelAndImageView *labelAndImageView;
@property(nonatomic, strong) IBOutlet UILabel *label;
@end

今回は自作のUITableViewCellであるMyCell1にLabelAndImageViewとUILabelを置いてみます。
LabelAndImageViewのIBOutletを作ります。

スクリーンショット 2013-08-03 14.13.25
Interface BuilderでLabelAndImageViewを配置するには、UIViewを置き、後からクラスをLabelAndImageViewに変更します。
同じくIBOutletと接続しておしまい。

ファイルが散らかってますが、サンプルコードはgithubに置きました。