せでぃのブログ

ブログ初心者おいどんのどうでもいい愚痴やどうでもいい愚痴やどうでもいいマメ知識などを披露するチラシの裏です。

Objective-Cでtableviewをカスタムセルで作ってスワイプで削除してみた

20150411修正:「9.1.ストーリーボードのTableView紐付け」の項目を削除、githubも修正
20150404追記:お勧めできない項目追加
20150327追記:ページ最下に関連記事の項目追記
同日修正:紛らわしかったxibのファイル名を変えて、差し替え版を上げました。
 今回、参考にした記事はこの辺。dev.classmethod.jp
hetyo-pg.blog.jp
 本当はSWTableViewCellというアドオン拡張的なものを使うと楽らしいのだが、ここはswiftを見越してできるだけ拡張せずにやってみた。機能テスト的な感じでいじった。
http://pickslife.me/cocoa-pods-search
 既にswiftでセルのスライドをテストしてる人もいるというね。さすがはてなーですわ。
AutoLayoutでスワイプできるUITableViewCellを実装する - tomoyaonishiのブログ


 ものはここに上げた。
csny/swipe-customcell · GitHub

今回の作りはお勧めできない

f:id:Sediment:20150404221733p:plain
 こんな記事作っといてなんだけど、実はxibを使う方法はお勧めできない。わざわざxibに分ける理由が見つからないのだ。カスタマイズといいセル高の自動調整とい、StoryBoard上でできないことはないと思っていい。やるとしたら推奨構成の形がいいと思う。

完成画像

 右スワイプをswipe gesture recognizerでお手軽に実装し、NSLogだけしてみる。データの入ったセルではindexpath.rowを、入っていないセルではスワイプ無効という表示を出した。
f:id:Sediment:20150317003411p:plain
 左スワイプをすると、editActionsForRowAtIndexPath:によりボタンっぽいものが出る。iOS8かららしいが、ネット上の噂によるとiOS7でも出てくるらしい。
f:id:Sediment:20150317003429p:plain
 削除機能のみ実装した。
f:id:Sediment:20150317003438p:plain

作成手順

1.xcodeの初期設定
 SingleViewで始める。名前や保存場所は適当に。
f:id:Sediment:20150305011427p:plain


2.ストーリーボードにある既存のviewcontrollerとクラスファイルViewController.mと.hを削除
f:id:Sediment:20150306154039p:plain
f:id:Sediment:20150306173605p:plain


3.ストーリーボードのオブジェクト及びクラスファイルを新規作成
 ストーリーボードの何もない空間にNavigationControllerを追加。
f:id:Sediment:20150306153647p:plain
 NewFileからクラスファイルを新規作成し、CocoaTouchClass→UITableViewControllerサブクラスの「RootViewController」というクラス名のファイルを作る。
f:id:Sediment:20150317010834p:plain


4.xibファイルの新規作成
 GUIでセルをカスタマイズしたいので、NewFileからUser Interface→Emptyを選択。
f:id:Sediment:20150317010132p:plain
 ここでは、「XibCustomCell.xib」という名前にしておく。
f:id:Sediment:20150317164934p:plain


5.xibへオブジェクト及びクラスファイルを新規作成
 作成した空のxib内にTableViewCellを新規追加。適当にLabelやボタンなどを配置。今回はラベルのみ。
f:id:Sediment:20150317011151p:plain
 NewFileからCocoaTouchClass→UITableViewCellサブクラスの「CustomTableViewCell」というクラス名のファイルを作る。
f:id:Sediment:20150317011440p:plain


6.「NavigationController」を最初に起動するオブジェクトとして設定
 ストーリーボードの「NavigationController」のAttributes inspectorの「is Initial View Controller」にチェックを入れる。
f:id:Sediment:20150306164613p:plain


7.オブジェクトとクラスファイルの紐付け
 7.1.ストーリーボード
 3.で作ったクラスファイル名「RootViewController」をストーリーボードでRootViewControllerのClassに貼り付けて、リターン。Classの項目は、Identity inspectorにある。
f:id:Sediment:20150317012008p:plain

 7.2.xib
 4.で作ったクラスファイル名「CustomTableViewCell」を、xib上でTableViewCellの一番上位にあるオブジェクトのClassに貼り付けて、リターン。
f:id:Sediment:20150317012302p:plain
Classの項目は、Identity inspectorにある。
f:id:Sediment:20150317012318p:plain


8.セルのオブジェクト設定
 8.1.ストーリーボードのTableViewの付属のセルを削除
 ストーリーボードのRootViewController内のTableViewを選択し、Prototype Cellsを0に変更して、ContentのDynamicやselectionのSingleを確認。
f:id:Sediment:20150317012851p:plain

 8.2.xibのカスタマイズセルにIdentifierを設定
 TableViewCellの一番上位にあるオブジェクトのidに「Cell」を入力して、リターン。
f:id:Sediment:20150317013235p:plain


9.オブジェクトの紐付け
 9.1.xibのラベル位置調整とセルの幅決定
 xibを開き、5.でカスタムセルに貼り付けたラベルやボタンの位置を修正しつつ、セルの幅を調整し決定します。ここでは「60.0」にしました。
f:id:Sediment:20150317142600p:plain
 TableViewCellを選択、Size inspectorを開くとRow Heightが60.0に変わり、Customにチェックが入っているはずです。セルを掴みながら幅を動かすと、ここの値も随時変わるのが見られるでしょう。あとで使うのでこの数値を覚えておきます。
f:id:Sediment:20150317144416p:plain

 9.2.xibのラベル紐付け
 xibの画面で、Assistant editorで右側に「CustomTableViewCell.h」を開き、5.でカスタムセルに貼り付けたラベルやボタン全てについて、@interfaceの下の行あたりにControl+ドラッグ&ドロップ。
f:id:Sediment:20150317023809p:plain
Outletのまま、適当に名前をつける。今回使う分として「labelDate」のみキッチリ名前を付ける。ボタンなどActionが必要であればActionで配置。
f:id:Sediment:20150317023832p:plain


10.右スワイプ機能の準備
 Swipe Gesture RecognizerをRootViewControllerへドロップ。
f:id:Sediment:20150317015449p:plain
 Swipe Gesture RecognizerのConnections inspectorを開き、Referencing Outlet CollectionsからRootViewControllerのTableViewへドロップしてgestureRecognizersを選択。画像は既に全部実施した後の状態なので、最終的にはこのようなコネクションになる。
f:id:Sediment:20150317015635p:plain
 Swipe Gesture RecognizerのAttribute inspectorを開き、swipeをRIGHTに設定。これで右向きのスワイプしか受け付けない。
f:id:Sediment:20150317020738p:plain
 Assistant editorで右側に「RootViewController.h」を開き、Swipe Gesture Recognizerから@interfaceの下の行あたりへControl+ドラッグ&ドロップ。
f:id:Sediment:20150317022456p:plain
 Actionを選択して、「swipedRight」と名付ける。
f:id:Sediment:20150317020952p:plain


11.カスタムセルの幅を通知する準備
 9.2.でTableViewCellの幅として決めた「60.0」をここで使います。
 以下のファイルへ以下のコードを入力。
 「+」でメソッドを定義しているのがミソです。これをクラスメソッドと言い、「ー」で宣言するインスタンスメソッドとは呼び出し方が変わります。詳しくはクラス変数、インスタンス変数でググるといいかも。
CustomTableViewCell.h

// クラスメソッド宣言
+ (CGFloat)rowHeight;

CustomTableViewCell.m

// セルの高さのクラスメソッド
+ (CGFloat)rowHeight
{
    return 60.0f;
}


12.RootViewControllerへCustomTableViewCellのインポート
 「RootViewController.h」の冒頭に以下を追記。

#import "CustomTableViewCell.h"


13.インスタンス変数を宣言しておく
 配列を入れて使い回すために、インスタンス変数を1つ作っておく。「RootViewController.h」の@interfaceの下あたりに以下を追記。今回は配列の要素を削除する操作を入れたいので、NSMutableArrayで宣言。

// property*iphoneModelsは手入力、インスタンス変数iphoneModelsを準備
@property NSMutableArray *iphoneModels;

 貼り付け後の「RootViewController.h」はこうなっているはず。
swipe-customcell/RootViewController.h at master · csny/swipe-customcell · GitHub


14.「RootViewController.m」へコード入力
 以下、不明なところはコードを見てもらった方が早いかも。
swipe-customcell/RootViewController.m at master · csny/swipe-customcell · GitHub

 14.1.xibファイルをコードへ紐付け
 @implementationの上の行あたりに以下のコードを入れることで、xibファイルをstatic指定子でクラス変数として宣言&初期化。xibを呼び出す処理は次の項目で説明する。

/*
 サムネイル・デバイス名・セル番号で構成されたカスタムセルのID
 "XibCustomCell.xib"ファイルとの紐付け
 */
static NSString * const TableViewCustomCellIdentifier = @"XibCustomCell";

 14.2.viewDidLoad編集
 配列の初期化をして、カスタマイズしたxibのセルをtableViewに呼び出す処理。

- (void)viewDidLoad {
    [super viewDidLoad];
    // テーブルに表示したい配列を用意
    _iphoneModels = [NSMutableArray arrayWithObjects:@"iPhone 4", @"iPhone 4S", @"iPhone 5", @"iPhone 5c", @"iPhone 5s", @"iPhone 6c", @"iPhone 6 plus", nil];
    
    // カスタマイズしたセルをテーブルビューにセット
    UINib *nib = [UINib nibWithNibName:TableViewCustomCellIdentifier bundle:nil];
    [self.tableView registerNib:nib forCellReuseIdentifier:@"Cell"];
}

 14.3.カスタムセルの高さをtableviewに通知
 heightForRowAtIndexPath:メソッドを作成。普段あんまり使わんね。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [CustomTableViewCell rowHeight];
}

 14.4.tableviewに配列を書き出す
 必須の2つのメソッドを丸ごと追記。cellForRowAtIndexPath:の方はファイル内に既に記載されてるはずなので、書き換えても可。普段と違うのは、CustomTableViewCellをインスタンス化するところか。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//省略
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//省略
}

 14.5.左スワイプの設定
 以下のメソッドを追記するだけ。左スワイプによるeditボタンなどは、以下の2つのメソッドをコードで書くだけで簡単に実装できる。

//UITableViewDelegateに追加された編集・削除メソッドiOS8から
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
//省略
}
// iOS7で必須。iOS8では不要。
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//省略
}

 14.6.右スワイプの処理
 10.で既に設定しておいたswipeアクション時のメソッド内に処理を記載する。

// 右スワイプ時の動作定義
- (IBAction)swipedRight:(id)sender {
//省略
}

 できあがり。

関連記事

 カスタマイズセルの高さを自動調整してみたけど、まぁうまくいかんね。
cocoaのセルの高さ自動調整機能は未完成な気がしたけど、そんなこともなかったぜ - せでぃのブログ